From 213b181dbe910d2b01fda9a7457bccc78c4963d1 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 14 Nov 2023 16:07:55 -0500 Subject: [PATCH 01/52] dt-bindings: mmc: sdhci-of-dwcmhsc: Add T-Head TH1520 support Add compatible value for the T-Head TH1520 dwcmshc controller. Acked-by: Guo Ren Acked-by: Krzysztof Kozlowski Signed-off-by: Drew Fustini --- Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml index a43eb837f8dae0..42804d95529342 100644 --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml @@ -19,6 +19,7 @@ properties: - rockchip,rk3568-dwcmshc - rockchip,rk3588-dwcmshc - snps,dwcmshc-sdhci + - thead,th1520-dwcmshc reg: maxItems: 1 From e7b5a9b1de0e3eddbddc4cde48129a57e61c4915 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 14 Nov 2023 16:07:56 -0500 Subject: [PATCH 02/52] mmc: sdhci: add __sdhci_execute_tuning() to header Expose __sdhci_execute_tuning() so that it can be called from the mmc host controller drivers. In the sdhci-of-dwcmshc driver, sdhci_dwcmshc_th1520_ops sets platform_execute_tuning to th1520_execute_tuning(). That function has to manipulate phy registers before tuning can be performed. To avoid copying the code verbatim from __sdhci_execute_tuning() into th1520_execute_tuning(), make it possible for __sdhci_execute_tuning() to be called from sdhci-of-dwcmshc. Acked-by: Adrian Hunter Signed-off-by: Drew Fustini --- drivers/mmc/host/sdhci.c | 3 ++- drivers/mmc/host/sdhci.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ff41aa56564eaa..c79f73459915d4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2841,7 +2841,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) } EXPORT_SYMBOL_GPL(sdhci_send_tuning); -static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) { int i; @@ -2879,6 +2879,7 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) sdhci_reset_tuning(host); return -EAGAIN; } +EXPORT_SYMBOL_GPL(__sdhci_execute_tuning); int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index f219bdea8f280d..a20864fc064127 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -793,6 +793,7 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width); void sdhci_reset(struct sdhci_host *host, u8 mask); void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); +int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode); void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios); From 184924fa4e1793c24c665f105f9b7b71857ca2fb Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 14 Nov 2023 16:07:57 -0500 Subject: [PATCH 03/52] mmc: sdhci-of-dwcmshc: Add support for T-Head TH1520 Add support for the mmc controller in the T-Head TH1520 with the new compatible "thead,th1520-dwcmshc". Implement custom sdhci_ops for set_uhs_signaling, reset, voltage_switch, and platform_execute_tuning. Acked-by: Adrian Hunter Signed-off-by: Drew Fustini Reviewed-by: Jisheng Zhang --- drivers/mmc/host/sdhci-of-dwcmshc.c | 349 ++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 3a3bae6948a899..0eb72544c09ed5 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -35,6 +36,21 @@ #define DWCMSHC_CARD_IS_EMMC BIT(0) #define DWCMSHC_ENHANCED_STROBE BIT(8) #define DWCMSHC_EMMC_ATCTRL 0x40 +/* Tuning and auto-tuning fields in AT_CTRL_R control register */ +#define AT_CTRL_AT_EN BIT(0) /* autotuning is enabled */ +#define AT_CTRL_CI_SEL BIT(1) /* interval to drive center phase select */ +#define AT_CTRL_SWIN_TH_EN BIT(2) /* sampling window threshold enable */ +#define AT_CTRL_RPT_TUNE_ERR BIT(3) /* enable reporting framing errors */ +#define AT_CTRL_SW_TUNE_EN BIT(4) /* enable software managed tuning */ +#define AT_CTRL_WIN_EDGE_SEL_MASK GENMASK(11, 8) /* bits [11:8] */ +#define AT_CTRL_WIN_EDGE_SEL 0xf /* sampling window edge select */ +#define AT_CTRL_TUNE_CLK_STOP_EN BIT(16) /* clocks stopped during phase code change */ +#define AT_CTRL_PRE_CHANGE_DLY_MASK GENMASK(18, 17) /* bits [18:17] */ +#define AT_CTRL_PRE_CHANGE_DLY 0x1 /* 2-cycle latency */ +#define AT_CTRL_POST_CHANGE_DLY_MASK GENMASK(20, 19) /* bits [20:19] */ +#define AT_CTRL_POST_CHANGE_DLY 0x3 /* 4-cycle latency */ +#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */ +#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */ /* Rockchip specific Registers */ #define DWCMSHC_EMMC_DLL_CTRL 0x800 @@ -72,6 +88,82 @@ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) #define RK35xx_MAX_CLKS 3 +/* PHY register area pointer */ +#define DWC_MSHC_PTR_PHY_R 0x300 + +/* PHY general configuration */ +#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) +#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */ +#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits [19:16] */ +#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */ +#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits [23:20] */ +#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */ + +/* PHY command/response pad settings */ +#define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04) + +/* PHY data pad settings */ +#define PHY_DATAPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x06) + +/* PHY clock pad settings */ +#define PHY_CLKPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x08) + +/* PHY strobe pad settings */ +#define PHY_STBPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0a) + +/* PHY reset pad settings */ +#define PHY_RSTNPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0c) + +/* Bitfields are common for all pad settings */ +#define PHY_PAD_RXSEL_1V8 0x1 /* Receiver type select for 1.8V */ +#define PHY_PAD_RXSEL_3V3 0x2 /* Receiver type select for 3.3V */ + +#define PHY_PAD_WEAKPULL_MASK GENMASK(4, 3) /* bits [4:3] */ +#define PHY_PAD_WEAKPULL_PULLUP 0x1 /* Weak pull up enabled */ +#define PHY_PAD_WEAKPULL_PULLDOWN 0x2 /* Weak pull down enabled */ + +#define PHY_PAD_TXSLEW_CTRL_P_MASK GENMASK(8, 5) /* bits [8:5] */ +#define PHY_PAD_TXSLEW_CTRL_P 0x3 /* Slew control for P-Type pad TX */ +#define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9) /* bits [12:9] */ +#define PHY_PAD_TXSLEW_CTRL_N 0x3 /* Slew control for N-Type pad TX */ + +/* PHY CLK delay line settings */ +#define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) +#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */ + +/* PHY CLK delay line delay code */ +#define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e) +#define PHY_SDCLKDL_DC_INITIAL 0x40 /* initial delay code */ +#define PHY_SDCLKDL_DC_DEFAULT 0x32 /* default delay code */ +#define PHY_SDCLKDL_DC_HS400 0x18 /* delay code for HS400 mode */ + +/* PHY drift_cclk_rx delay line configuration setting */ +#define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21) +#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2) /* bits [3:2] */ +#define PHY_ATDL_CNFG_INPSEL 0x3 /* delay line input source */ + +/* PHY DLL control settings */ +#define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24) +#define PHY_DLL_CTRL_DISABLE 0x0 /* PHY DLL is enabled */ +#define PHY_DLL_CTRL_ENABLE 0x1 /* PHY DLL is disabled */ + +/* PHY DLL configuration register 1 */ +#define PHY_DLL_CNFG1_R (DWC_MSHC_PTR_PHY_R + 0x25) +#define PHY_DLL_CNFG1_SLVDLY_MASK GENMASK(5, 4) /* bits [5:4] */ +#define PHY_DLL_CNFG1_SLVDLY 0x2 /* DLL slave update delay input */ +#define PHY_DLL_CNFG1_WAITCYCLE 0x5 /* DLL wait cycle input */ + +/* PHY DLL configuration register 2 */ +#define PHY_DLL_CNFG2_R (DWC_MSHC_PTR_PHY_R + 0x26) +#define PHY_DLL_CNFG2_JUMPSTEP 0xa /* DLL jump step input */ + +/* PHY DLL master and slave delay line configuration settings */ +#define PHY_DLLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x28) +#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5) /* bits [6:5] */ +#define PHY_DLLDL_CNFG_SLV_INPSEL 0x3 /* clock source select for slave DL */ + +#define FLAG_IO_FIXED_1V8 BIT(0) + #define BOUNDARY_OK(addr, len) \ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) @@ -92,6 +184,8 @@ struct dwcmshc_priv { struct clk *bus_clk; int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ void *priv; /* pointer to SoC private stuff */ + u16 delay_line; + u16 flags; }; /* @@ -157,6 +251,127 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_request(mmc, mrq); } +static void dwcmshc_phy_1_8v_init(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 val; + + /* deassert phy reset & set tx drive strength */ + val = PHY_CNFG_RSTN_DEASSERT; + val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); + val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); + sdhci_writel(host, val, PHY_CNFG_R); + + /* disable delay line */ + sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); + + /* set delay line */ + sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); + sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); + + /* enable delay lane */ + val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE); + sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); + + /* configure phy pads */ + val = PHY_PAD_RXSEL_1V8; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); + sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); + sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); + + val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); + + val = PHY_PAD_RXSEL_1V8; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_STBPAD_CNFG_R); + + /* enable data strobe mode */ + sdhci_writeb(host, FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL), + PHY_DLLDL_CNFG_R); + + /* enable phy dll */ + sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); +} + +static void dwcmshc_phy_3_3v_init(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 val; + + /* deassert phy reset & set tx drive strength */ + val = PHY_CNFG_RSTN_DEASSERT; + val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); + val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); + sdhci_writel(host, val, PHY_CNFG_R); + + /* disable delay line */ + sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); + + /* set delay line */ + sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); + sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); + + /* enable delay lane */ + val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE); + sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); + + /* configure phy pads */ + val = PHY_PAD_RXSEL_3V3; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); + sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); + sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); + + val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); + + val = PHY_PAD_RXSEL_3V3; + val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); + val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); + sdhci_writew(host, val, PHY_STBPAD_CNFG_R); + + /* enable phy dll */ + sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); +} + +static void th1520_sdhci_set_phy(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + u16 emmc_ctrl; + + /* Before power on, set PHY configs */ + if (priv->flags & FLAG_IO_FIXED_1V8) + dwcmshc_phy_1_8v_init(host); + else + dwcmshc_phy_3_3v_init(host); + + if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { + emmc_ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); + emmc_ctrl |= DWCMSHC_CARD_IS_EMMC; + sdhci_writew(host, emmc_ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); + } + + sdhci_writeb(host, FIELD_PREP(PHY_DLL_CNFG1_SLVDLY_MASK, PHY_DLL_CNFG1_SLVDLY) | + PHY_DLL_CNFG1_WAITCYCLE, PHY_DLL_CNFG1_R); +} + static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) { @@ -189,9 +404,25 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, ctrl_2 |= DWCMSHC_CTRL_HS400; } + if (priv->flags & FLAG_IO_FIXED_1V8) + ctrl_2 |= SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } +static void th1520_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + + dwcmshc_set_uhs_signaling(host, timing); + if (timing == MMC_TIMING_MMC_HS400) + priv->delay_line = PHY_SDCLKDL_DC_HS400; + else + sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R); + th1520_sdhci_set_phy(host); +} + static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -338,6 +569,79 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_reset(host, mask); } +static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u32 val = 0; + + if (host->flags & SDHCI_HS400_TUNING) + return 0; + + sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL), + PHY_ATDL_CNFG_R); + val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + + /* + * configure tuning settings: + * - center phase select code driven in block gap interval + * - disable reporting of framing errors + * - disable software managed tuning + * - disable user selection of sampling window edges, + * instead tuning calculated edges are used + */ + val &= ~(AT_CTRL_CI_SEL | AT_CTRL_RPT_TUNE_ERR | AT_CTRL_SW_TUNE_EN | + FIELD_PREP(AT_CTRL_WIN_EDGE_SEL_MASK, AT_CTRL_WIN_EDGE_SEL)); + + /* + * configure tuning settings: + * - enable auto-tuning + * - enable sampling window threshold + * - stop clocks during phase code change + * - set max latency in cycles between tx and rx clocks + * - set max latency in cycles to switch output phase + * - set max sampling window threshold value + */ + val |= AT_CTRL_AT_EN | AT_CTRL_SWIN_TH_EN | AT_CTRL_TUNE_CLK_STOP_EN; + val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY); + val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY); + val |= FIELD_PREP(AT_CTRL_SWIN_TH_VAL_MASK, AT_CTRL_SWIN_TH_VAL); + + sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + + /* perform tuning */ + sdhci_start_tuning(host); + host->tuning_err = __sdhci_execute_tuning(host, opcode); + if (host->tuning_err) { + /* disable auto-tuning upon tuning error */ + val &= ~AT_CTRL_AT_EN; + sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); + dev_err(mmc_dev(host->mmc), "tuning failed: %d\n", host->tuning_err); + return -EIO; + } + sdhci_end_tuning(host); + + return 0; +} + +static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u16 ctrl_2; + + sdhci_reset(host, mask); + + if (priv->flags & FLAG_IO_FIXED_1V8) { + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (!(ctrl_2 & SDHCI_CTRL_VDD_180)) { + ctrl_2 |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + } + } +} + static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, @@ -356,6 +660,17 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { .adma_write_desc = dwcmshc_adma_write_desc, }; +static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = th1520_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, + .reset = th1520_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + .voltage_switch = dwcmshc_phy_1_8v_init, + .platform_execute_tuning = &th1520_execute_tuning, +}; + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { .ops = &sdhci_dwcmshc_ops, .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, @@ -379,6 +694,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; +static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = { + .ops = &sdhci_dwcmshc_th1520_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +}; + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) { int err; @@ -447,6 +768,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "snps,dwcmshc-sdhci", .data = &sdhci_dwcmshc_pdata, }, + { + .compatible = "thead,th1520-dwcmshc", + .data = &sdhci_dwcmshc_th1520_pdata, + }, {}, }; MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); @@ -542,6 +867,30 @@ static int dwcmshc_probe(struct platform_device *pdev) goto err_clk; } + if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { + priv->delay_line = PHY_SDCLKDL_DC_DEFAULT; + + if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) | + (device_property_read_bool(dev, "mmc-hs200-1_8v")) | + (device_property_read_bool(dev, "mmc-hs400-1_8v"))) + priv->flags |= FLAG_IO_FIXED_1V8; + else + priv->flags &= ~FLAG_IO_FIXED_1V8; + + /* + * start_signal_voltage_switch() will try 3.3V first + * then 1.8V. Use SDHCI_SIGNALING_180 rather than + * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V + * in sdhci_start_signal_voltage_switch(). + */ + if (priv->flags & FLAG_IO_FIXED_1V8) { + host->flags &= ~SDHCI_SIGNALING_330; + host->flags |= SDHCI_SIGNALING_180; + } + + sdhci_enable_v4_mode(host); + } + #ifdef CONFIG_ACPI if (pltfm_data == &sdhci_dwcmshc_bf3_pdata) sdhci_enable_v4_mode(host); From d5208c708d1f3bfce2715b3601f89802ae1569d1 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 14 Nov 2023 16:07:58 -0500 Subject: [PATCH 04/52] riscv: defconfig: Enable mmc and dma drivers for T-Head TH1520 Enable the mmc controller driver and dma controller driver needed for T-Head TH1520 based boards, like the LicheePi 4A and BeagleV-Ahead, to boot from eMMC storage. Reviewed-by: Guo Ren Signed-off-by: Drew Fustini --- arch/riscv/configs/defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index ab86ec3b9eabcd..c5a8583236d01e 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -168,12 +168,14 @@ CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_CADENCE=y +CONFIG_MMC_SDHCI_OF_DWCMSHC=y CONFIG_MMC_SPI=y CONFIG_MMC_SUNXI=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_SUN6I=y CONFIG_DMADEVICES=y CONFIG_DMA_SUN6I=m +CONFIG_DW_AXI_DMAC=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y From fcdb0e3988dac8cdabcca3d08c36576af7769606 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 14 Nov 2023 16:07:59 -0500 Subject: [PATCH 05/52] riscv: dts: thead: Add TH1520 mmc controllers and sdhci clock Add node for the SDHCI fixed clock. Add mmc0 node for the first mmc controller instance which is typically connected to the eMMC device. Add mmc1 node for the second mmc controller instance which is typically connected to microSD slot. Signed-off-by: Drew Fustini --- arch/riscv/boot/dts/thead/th1520.dtsi | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index ff364709a6dfaf..fb8a4a04d3c435 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -134,6 +134,13 @@ #clock-cells = <0>; }; + sdhci_clk: sdhci-clock { + compatible = "fixed-clock"; + clock-frequency = <198000000>; + clock-output-names = "sdhci_clk"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&plic>; @@ -292,6 +299,24 @@ status = "disabled"; }; + mmc0: mmc@ffe7080000 { + compatible = "thead,th1520-dwcmshc"; + reg = <0xff 0xe7080000 0x0 0x10000>; + interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sdhci_clk>; + clock-names = "core"; + status = "disabled"; + }; + + mmc1: mmc@ffe7090000 { + compatible = "thead,th1520-dwcmshc"; + reg = <0xff 0xe7090000 0x0 0x10000>; + interrupts = <64 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sdhci_clk>; + clock-names = "core"; + status = "disabled"; + }; + timer0: timer@ffefc32000 { compatible = "snps,dw-apb-timer"; reg = <0xff 0xefc32000 0x0 0x14>; From 3afcdf37e0dfcef091da5a0cc6fb948b068f85e6 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 14 Nov 2023 16:08:00 -0500 Subject: [PATCH 06/52] riscv: dts: thead: Enable BeagleV Ahead eMMC and microSD Add mmc0 properties for the eMMC device and add mmc1 properties for the microSD slot. Set the frequency for the sdhci clock. Signed-off-by: Drew Fustini --- .../boot/dts/thead/th1520-beaglev-ahead.dts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts index 70e8042c83046b..f91d94f955102b 100644 --- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts +++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts @@ -48,6 +48,10 @@ clock-frequency = <62500000>; }; +&sdhci_clk { + clock-frequency = <198000000>; +}; + &uart_sclk { clock-frequency = <100000000>; }; @@ -56,6 +60,22 @@ status = "okay"; }; +&mmc0 { + bus-width = <8>; + max-frequency = <198000000>; + mmc-hs400-1_8v; + non-removable; + no-sdio; + no-sd; + status = "okay"; +}; + +&mmc1 { + max-frequency = <198000000>; + bus-width = <4>; + status = "okay"; +}; + &uart0 { status = "okay"; }; From ae276cd44d8282c5ec28d1361583c313fb87f812 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 14 Nov 2023 16:08:01 -0500 Subject: [PATCH 07/52] riscv: dts: thead: Enable LicheePi 4A eMMC and microSD Add mmc0 properties for the eMMC device and add mmc1 properties for the microSD slot. Set the frequency for the sdhci clock. Signed-off-by: Drew Fustini --- .../dts/thead/th1520-lichee-module-4a.dtsi | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index a802ab1104294b..94f1741435a51e 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -29,6 +29,10 @@ clock-frequency = <62500000>; }; +&sdhci_clk { + clock-frequency = <198000000>; +}; + &uart_sclk { clock-frequency = <100000000>; }; @@ -36,3 +40,19 @@ &dmac0 { status = "okay"; }; + +&mmc0 { + bus-width = <8>; + max-frequency = <198000000>; + mmc-hs400-1_8v; + non-removable; + no-sdio; + no-sd; + status = "okay"; +}; + +&mmc1 { + max-frequency = <198000000>; + bus-width = <4>; + status = "okay"; +}; From 0a5cbd62600086a34eb944c68429f30b240c98b8 Mon Sep 17 00:00:00 2001 From: Kwanghoon Son Date: Mon, 4 Sep 2023 04:25:57 +0000 Subject: [PATCH 08/52] dt-bindings: reset: Document th1520 reset control Add documentation to describe th1520 reset driver Signed-off-by: Kwanghoon Son --- .../bindings/reset/thead,th1520-reset.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml diff --git a/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml new file mode 100644 index 00000000000000..a56d77af464a65 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reset/thead,th1520-reset.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD th1520 SoC Reset Controller + +maintainers: + - Kwanghoon Son + +properties: + compatible: + - items: + - const: thead,th1520-reset + - const: syscon + + reg: + maxItems: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + - '#reset-cells' + +additionalProperties: false + +examples: + - | + #include + + reset-controller@ffef014000 { + compatible = "thead,th1520-reset", "syscon"; + reg = <0xff 0xef014000 0x0 0x1000>; + #reset-cells = <1>; + }; From c23a0221c223ac1ab60ec5a4f8feed82326579ed Mon Sep 17 00:00:00 2001 From: Kwanghoon Son Date: Mon, 4 Sep 2023 04:25:58 +0000 Subject: [PATCH 09/52] reset: Add th1520 reset driver support This driver supports th1520 T-HEAD SoC reset platform device. Signed-off-by: Kwanghoon Son --- drivers/reset/Kconfig | 10 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-th1520.c | 109 +++++++++++++++++++++++ include/dt-bindings/reset/th1520-reset.h | 9 ++ 4 files changed, 129 insertions(+) create mode 100644 drivers/reset/reset-th1520.c create mode 100644 include/dt-bindings/reset/th1520-reset.h diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index ccd59ddd76100a..ec69e6bbba6e5e 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -253,6 +253,16 @@ config RESET_SUNXI help This enables the reset driver for Allwinner SoCs. +config RESET_TH1520 + bool "TH1520 Reset Driver" + depends on (ARCH_THEAD || COMPILE_TEST) && OF + select MFD_SYSCON + default ARCH_THEAD + help + Support for the T-HEAD 1520 RISC-V SoC reset controller. + Say Y if you want to control reset signals provided by this + controller. + config RESET_TI_SCI tristate "TI System Control Interface (TI-SCI) reset driver" depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8270da8a4baa62..5c858e62241a99 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o +obj-$(CONFIG_RESET_TH1520) += reset-th1520.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_TI_TPS380X) += reset-tps380x.o diff --git a/drivers/reset/reset-th1520.c b/drivers/reset/reset-th1520.c new file mode 100644 index 00000000000000..4c781377ac23e3 --- /dev/null +++ b/drivers/reset/reset-th1520.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include + +struct th1520_rst_signal { + unsigned int offset, bit; +}; + +struct th1520_rst { + struct reset_controller_dev rcdev; + struct regmap *regmap; + const struct th1520_rst_signal *signals; +}; + +enum th1520_rst_registers { + RST_WDT0 = 0x0034, + RST_WDT1 = 0x0038, +}; + +static int th1520_reset_update(struct th1520_rst *rst, unsigned long id, + unsigned int value) +{ + const struct th1520_rst_signal *signal = &rst->signals[id]; + + return regmap_update_bits(rst->regmap, signal->offset, signal->bit, + value); +} + +static const struct th1520_rst_signal th1520_rst_signals[] = { + [TH1520_RESET_WDT0] = { RST_WDT0, BIT(0) }, + [TH1520_RESET_WDT1] = { RST_WDT1, BIT(0) }, +}; + +static struct th1520_rst *to_th1520_rst(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct th1520_rst, rcdev); +} + +static int th1520_reset_set(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct th1520_rst *rst = to_th1520_rst(rcdev); + const unsigned int bit = rst->signals[id].bit; + unsigned int value = assert ? bit : 0; + + return th1520_reset_update(rst, id, value); +} + +static int th1520_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return th1520_reset_set(rcdev, id, false); +} + +static int th1520_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return th1520_reset_set(rcdev, id, true); +} + +static const struct reset_control_ops th1520_rst_ops = { + .assert = th1520_reset_assert, + .deassert = th1520_reset_deassert, +}; + +static int th1520_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct th1520_rst *rst; + struct regmap_config config = { .name = "rst" }; + + rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); + if (!rst) + return -ENOMEM; + + rst->signals = th1520_rst_signals; + rst->regmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(rst->regmap)) + return PTR_ERR(rst->regmap); + + regmap_attach_dev(dev, rst->regmap, &config); + + rst->rcdev.owner = THIS_MODULE; + rst->rcdev.dev = dev; + rst->rcdev.of_node = dev->of_node; + rst->rcdev.ops = &th1520_rst_ops; + rst->rcdev.nr_resets = ARRAY_SIZE(th1520_rst_signals); + + return devm_reset_controller_register(dev, &rst->rcdev); +} + +static const struct of_device_id th1520_reset_dt_ids[] = { + { .compatible = "thead,th1520-reset" }, + { /* sentinel */ }, +}; + +static struct platform_driver th1520_reset_driver = { + .probe = th1520_reset_probe, + .driver = { + .name = "th1520-reset", + .of_match_table = th1520_reset_dt_ids, + }, +}; +builtin_platform_driver(th1520_reset_driver); diff --git a/include/dt-bindings/reset/th1520-reset.h b/include/dt-bindings/reset/th1520-reset.h new file mode 100644 index 00000000000000..ec10751814e564 --- /dev/null +++ b/include/dt-bindings/reset/th1520-reset.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef DT_BINDING_RESET_TH1520_H +#define DT_BINDING_RESET_TH1520_H + +#define TH1520_RESET_WDT0 0 +#define TH1520_RESET_WDT1 1 + +#endif From 0566cd6e1c80ff1653416ed17ad6566433bb3ddc Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 27 Aug 2023 17:17:08 +0800 Subject: [PATCH 10/52] dt-bindings: net: snps,dwmac: allow dwmac-3.70a to set pbl properties snps dwmac 3.70a also supports setting pbl related properties, such as "snps,pbl", "snps,txpbl", "snps,rxpbl" and "snps,no-pbl-x8". Signed-off-by: Jisheng Zhang Reviewed-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/net/snps,dwmac.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index ddf9522a5dc230..b196c5de20615d 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -586,6 +586,7 @@ allOf: - qcom,sa8775p-ethqos - qcom,sc8280xp-ethqos - snps,dwmac-3.50a + - snps,dwmac-3.70a - snps,dwmac-4.10a - snps,dwmac-4.20a - snps,dwmac-5.20 From 77d9cccd47940df7a72499981bb77106afedee0b Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 27 Aug 2023 17:17:09 +0800 Subject: [PATCH 11/52] dt-bindings: net: add T-HEAD dwmac support Add documentation to describe T-HEAD dwmac. Signed-off-by: Jisheng Zhang --- .../devicetree/bindings/net/snps,dwmac.yaml | 1 + .../devicetree/bindings/net/thead,dwmac.yaml | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/thead,dwmac.yaml diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index b196c5de20615d..73821f86a60959 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -96,6 +96,7 @@ properties: - snps,dwxgmac - snps,dwxgmac-2.10 - starfive,jh7110-dwmac + - thead,th1520-dwmac reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/net/thead,dwmac.yaml b/Documentation/devicetree/bindings/net/thead,dwmac.yaml new file mode 100644 index 00000000000000..bf8ec8ca275341 --- /dev/null +++ b/Documentation/devicetree/bindings/net/thead,dwmac.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/thead,dwmac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD DWMAC Ethernet controller + +maintainers: + - Jisheng Zhang + +select: + properties: + compatible: + contains: + enum: + - thead,th1520-dwmac + required: + - compatible + +properties: + compatible: + items: + - enum: + - thead,th1520-dwmac + - const: snps,dwmac-3.70a + + reg: + maxItems: 1 + + thead,gmacapb: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle to the syscon node that control ethernet + interface and timing delay. + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - interrupt-names + - phy-mode + - thead,gmacapb + +allOf: + - $ref: snps,dwmac.yaml# + +unevaluatedProperties: false + +examples: + - | + gmac0: ethernet@e7070000 { + compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; + reg = <0xe7070000 0x2000>; + clocks = <&clk 1>, <&clk 2>; + clock-names = "stmmaceth", "pclk"; + interrupts = <66>; + interrupt-names = "macirq"; + phy-mode = "rgmii-id"; + snps,fixed-burst; + snps,axi-config = <&stmmac_axi_setup>; + snps,pbl = <32>; + thead,gmacapb = <&gmacapb_syscon>; + phy-handle = <&phy0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; + }; From d775ed09cf0745a04528fa5b7e2b7277a1b2f640 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 27 Aug 2023 17:17:10 +0800 Subject: [PATCH 12/52] net: stmmac: add glue layer for T-HEAD TH1520 SoC Add dwmac glue driver to support the dwmac on the T-HEAD TH1520 SoC. Signed-off-by: Jisheng Zhang --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + .../net/ethernet/stmicro/stmmac/dwmac-thead.c | 302 ++++++++++++++++++ 3 files changed, 314 insertions(+) create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 25f2d42de406d6..f70de05335997b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -216,6 +216,17 @@ config DWMAC_SUN8I stmmac device driver. This driver is used for H3/A83T/A64 EMAC ethernet controller. +config DWMAC_THEAD + tristate "T-HEAD dwmac support" + depends on OF && (ARCH_THEAD || COMPILE_TEST) + select MFD_SYSCON + help + Support for ethernet controllers on T-HEAD RISC-V SoCs + + This selects the T-HEAD platform specific glue layer support for + the stmmac device driver. This driver is used for T-HEAD TH1520 + ethernet controller. + config DWMAC_IMX8 tristate "NXP IMX8 DWMAC support" default ARCH_MXC diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 5b57aee19267ff..d73171ed6ad7d6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o +obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.o obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c new file mode 100644 index 00000000000000..c66c67c777f041 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * T-HEAD DWMAC platform driver + * + * Copyright (C) 2021 Alibaba Group Holding Limited. + * Copyright (C) 2023 Jisheng Zhang + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stmmac_platform.h" + +#define GMAC_CLK_EN 0x00 +#define GMAC_TX_CLK_EN BIT(1) +#define GMAC_TX_CLK_N_EN BIT(2) +#define GMAC_TX_CLK_OUT_EN BIT(3) +#define GMAC_RX_CLK_EN BIT(4) +#define GMAC_RX_CLK_N_EN BIT(5) +#define GMAC_EPHY_REF_CLK_EN BIT(6) +#define GMAC_RXCLK_DELAY_CTRL 0x04 +#define GMAC_RXCLK_BYPASS BIT(15) +#define GMAC_RXCLK_INVERT BIT(14) +#define GMAC_RXCLK_DELAY_MASK GENMASK(4, 0) +#define GMAC_RXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x)) +#define GMAC_TXCLK_DELAY_CTRL 0x08 +#define GMAC_TXCLK_BYPASS BIT(15) +#define GMAC_TXCLK_INVERT BIT(14) +#define GMAC_TXCLK_DELAY_MASK GENMASK(4, 0) +#define GMAC_TXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x)) +#define GMAC_PLLCLK_DIV 0x0c +#define GMAC_PLLCLK_DIV_EN BIT(31) +#define GMAC_PLLCLK_DIV_MASK GENMASK(7, 0) +#define GMAC_PLLCLK_DIV_NUM(x) FIELD_PREP(GMAC_PLLCLK_DIV_MASK, (x)) +#define GMAC_GTXCLK_SEL 0x18 +#define GMAC_GTXCLK_SEL_PLL BIT(0) +#define GMAC_INTF_CTRL 0x1c +#define PHY_INTF_MASK BIT(0) +#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1) +#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0) +#define GMAC_TXCLK_OEN 0x20 +#define TXCLK_DIR_MASK BIT(0) +#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0) +#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1) + +#define GMAC_GMII_RGMII_RATE 125000000 +#define GMAC_MII_RATE 25000000 + +struct thead_dwmac { + struct plat_stmmacenet_data *plat; + struct regmap *apb_regmap; + struct device *dev; + u32 rx_delay; + u32 tx_delay; +}; + +static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) +{ + struct thead_dwmac *dwmac = plat->bsp_priv; + u32 phyif; + + switch (plat->interface) { + case PHY_INTERFACE_MODE_MII: + phyif = PHY_INTF_MII_GMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + phyif = PHY_INTF_RGMII; + break; + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->interface); + return -EINVAL; + }; + + regmap_write(dwmac->apb_regmap, GMAC_INTF_CTRL, phyif); + + return 0; +} + +static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) +{ + struct thead_dwmac *dwmac = plat->bsp_priv; + u32 txclk_dir; + + switch (plat->interface) { + case PHY_INTERFACE_MODE_MII: + txclk_dir = TXCLK_DIR_INPUT; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + txclk_dir = TXCLK_DIR_OUTPUT; + break; + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->interface); + return -EINVAL; + }; + + regmap_write(dwmac->apb_regmap, GMAC_TXCLK_OEN, txclk_dir); + + return 0; +} + +static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode) +{ + struct thead_dwmac *dwmac = priv; + struct plat_stmmacenet_data *plat = dwmac->plat; + unsigned long rate; + u32 div; + + switch (plat->interface) { + /* For MII, rxc/txc is provided by phy */ + case PHY_INTERFACE_MODE_MII: + return; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + rate = clk_get_rate(plat->stmmac_clk); + if (!rate || rate % GMAC_GMII_RGMII_RATE != 0 || + rate % GMAC_MII_RATE != 0) { + dev_err(dwmac->dev, "invalid gmac rate %ld\n", rate); + return; + } + + regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, GMAC_PLLCLK_DIV_EN, 0); + + switch (speed) { + case SPEED_1000: + div = rate / GMAC_GMII_RGMII_RATE; + break; + case SPEED_100: + div = rate / GMAC_MII_RATE; + break; + case SPEED_10: + div = rate * 10 / GMAC_MII_RATE; + break; + default: + dev_err(dwmac->dev, "invalid speed %u\n", speed); + return; + } + regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, + GMAC_PLLCLK_DIV_MASK, GMAC_PLLCLK_DIV_NUM(div)); + + regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, + GMAC_PLLCLK_DIV_EN, GMAC_PLLCLK_DIV_EN); + break; + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->interface); + return; + } +} + +static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) +{ + struct thead_dwmac *dwmac = plat->bsp_priv; + u32 reg; + + switch (plat->interface) { + case PHY_INTERFACE_MODE_MII: + reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + /* use pll */ + regmap_write(dwmac->apb_regmap, GMAC_GTXCLK_SEL, GMAC_GTXCLK_SEL_PLL); + + reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN | + GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN; + break; + + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->interface); + return -EINVAL; + } + + regmap_write(dwmac->apb_regmap, GMAC_CLK_EN, reg); + + return 0; +} + +static int thead_dwmac_init(struct platform_device *pdev, + struct plat_stmmacenet_data *plat) +{ + struct thead_dwmac *dwmac = plat->bsp_priv; + int ret; + + ret = thead_dwmac_set_phy_if(plat); + if (ret) + return ret; + + ret = thead_dwmac_set_txclk_dir(plat); + if (ret) + return ret; + + regmap_write(dwmac->apb_regmap, GMAC_RXCLK_DELAY_CTRL, + GMAC_RXCLK_DELAY_VAL(dwmac->rx_delay)); + regmap_write(dwmac->apb_regmap, GMAC_TXCLK_DELAY_CTRL, + GMAC_TXCLK_DELAY_VAL(dwmac->tx_delay)); + + thead_dwmac_fix_speed(dwmac, SPEED_1000, 0); + + return thead_dwmac_enable_clk(plat); +} + +static int thead_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat; + struct stmmac_resources stmmac_res; + struct thead_dwmac *dwmac; + struct device_node *np = pdev->dev.of_node; + u32 delay_ps; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to get resources\n"); + + plat = stmmac_probe_config_dt(pdev, stmmac_res.mac); + if (IS_ERR(plat)) + return dev_err_probe(&pdev->dev, PTR_ERR(plat), + "dt configuration failed\n"); + + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) { + ret = -ENOMEM; + goto err_remove_config_dt; + } + + if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay_ps)) + dwmac->rx_delay = delay_ps; + if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay_ps)) + dwmac->tx_delay = delay_ps; + + dwmac->apb_regmap = syscon_regmap_lookup_by_phandle(np, "thead,gmacapb"); + if (IS_ERR(dwmac->apb_regmap)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(dwmac->apb_regmap), + "Failed to get gmac apb syscon\n"); + goto err_remove_config_dt; + } + + dwmac->dev = &pdev->dev; + dwmac->plat = plat; + plat->bsp_priv = dwmac; + plat->fix_mac_speed = thead_dwmac_fix_speed; + + ret = thead_dwmac_init(pdev, plat); + if (ret) + goto err_remove_config_dt; + + ret = stmmac_dvr_probe(&pdev->dev, plat, &stmmac_res); + if (ret) + goto err_remove_config_dt; + + return 0; + +err_remove_config_dt: + stmmac_remove_config_dt(pdev, plat); + + return ret; +} + +static const struct of_device_id thead_dwmac_match[] = { + { .compatible = "thead,th1520-dwmac" }, + { } +}; +MODULE_DEVICE_TABLE(of, thead_dwmac_match); + +static struct platform_driver thead_dwmac_driver = { + .probe = thead_dwmac_probe, + .remove_new = stmmac_pltfr_remove, + .driver = { + .name = "thead-dwmac", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = thead_dwmac_match, + }, +}; +module_platform_driver(thead_dwmac_driver); + +MODULE_AUTHOR("T-HEAD"); +MODULE_AUTHOR("Jisheng Zhang "); +MODULE_DESCRIPTION("T-HEAD dwmac platform driver"); +MODULE_LICENSE("GPL"); From f0c903ca57ee59f9698144e92308d88741216a4c Mon Sep 17 00:00:00 2001 From: Han Gao Date: Thu, 21 Sep 2023 14:14:03 +0800 Subject: [PATCH 13/52] fix: dwmac-thead build error Signed-off-by: Han Gao --- .../net/ethernet/stmicro/stmmac/dwmac-thead.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c index c66c67c777f041..547f3d8fd2e355 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c @@ -66,7 +66,7 @@ static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) struct thead_dwmac *dwmac = plat->bsp_priv; u32 phyif; - switch (plat->interface) { + switch (plat->phy_interface) { case PHY_INTERFACE_MODE_MII: phyif = PHY_INTF_MII_GMII; break; @@ -78,7 +78,7 @@ static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) break; default: dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->interface); + plat->phy_interface); return -EINVAL; }; @@ -92,7 +92,7 @@ static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) struct thead_dwmac *dwmac = plat->bsp_priv; u32 txclk_dir; - switch (plat->interface) { + switch (plat->phy_interface) { case PHY_INTERFACE_MODE_MII: txclk_dir = TXCLK_DIR_INPUT; break; @@ -104,7 +104,7 @@ static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) break; default: dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->interface); + plat->phy_interface); return -EINVAL; }; @@ -120,7 +120,7 @@ static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int m unsigned long rate; u32 div; - switch (plat->interface) { + switch (plat->phy_interface) { /* For MII, rxc/txc is provided by phy */ case PHY_INTERFACE_MODE_MII: return; @@ -160,7 +160,7 @@ static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int m break; default: dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->interface); + plat->phy_interface); return; } } @@ -170,7 +170,7 @@ static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) struct thead_dwmac *dwmac = plat->bsp_priv; u32 reg; - switch (plat->interface) { + switch (plat->phy_interface) { case PHY_INTERFACE_MODE_MII: reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN; break; @@ -188,7 +188,7 @@ static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) default: dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->interface); + plat->phy_interface); return -EINVAL; } From 582ffd5857fda5bbdb9fe14c247bd26b04d4c24c Mon Sep 17 00:00:00 2001 From: Han Gao Date: Tue, 26 Sep 2023 10:11:19 +0800 Subject: [PATCH 14/52] [NFU] WIP on th_net: d3e1832c7d2d riscv: mm: update T-Head memory type definitions The patch from Jisheng Zhang Signed-off-by: Han Gao --- .../dts/thead/th1520-lichee-module-4a.dtsi | 8 ++ .../boot/dts/thead/th1520-lichee-pi-4a.dts | 25 ++++++ arch/riscv/boot/dts/thead/th1520.dtsi | 79 +++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index 94f1741435a51e..ba38b3e76b81ff 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -37,6 +37,14 @@ clock-frequency = <100000000>; }; +&gmac_clk { + clock-frequency = <500000000>; +}; + +&gmac_axi_clk { + clock-frequency = <100000000>; +}; + &dmac0 { status = "okay"; }; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 9a3884a73e1372..ccdcb580b27410 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -10,6 +10,8 @@ compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520"; aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; gpio0 = &gpio0; gpio1 = &gpio1; gpio2 = &gpio2; @@ -27,6 +29,29 @@ }; }; +&mdio0 { + phy0: ethernet-phy@1 { + reg = <1>; + }; +}; + +&gmac0 { + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&mdio1 { + phy1: ethernet-phy@2 { + reg = <2>; + }; +}; + +&gmac1 { + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; +}; + &uart0 { status = "okay"; }; diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index fb8a4a04d3c435..146d40bbbfea53 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -141,6 +141,18 @@ #clock-cells = <0>; }; + gmac_axi_clk: gmac-axi-clock { + compatible = "fixed-clock"; + clock-output-names = "gmac_axi_clk"; + #clock-cells = <0>; + }; + + gmac_clk: gmac-clock { + compatible = "fixed-clock"; + clock-output-names = "gmac_clk"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&plic>; @@ -171,6 +183,62 @@ <&cpu3_intc 3>, <&cpu3_intc 7>; }; + gmac0: ethernet@ffe7070000 { + compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; + reg = <0xff 0xe7070000 0x0 0x2000>; + interrupts = <66 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + clocks = <&gmac_clk>, <&gmac_axi_clk>; + clock-names = "stmmaceth", "pclk"; + snps,pbl = <32>; + snps,fixed-burst; + snps,multicast-filter-bins = <64>; + snps,perfect-filter-entries = <32>; + snps,axi-config = <&gmac0_stmmac_axi_setup>; + thead,gmacapb = <&gmacapb_syscon0>; + status = "disabled"; + + mdio0: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + + gmac0_stmmac_axi_setup: stmmac-axi-config { + snps,wr_osr_lmt = <0xf>; + snps,rd_osr_lmt = <0xf>; + snps,blen = <0 0 64 32 0 0 0>; + }; + }; + + gmac1: ethernet@ffe7060000 { + compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; + reg = <0xff 0xe7060000 0x0 0x2000>; + interrupts = <67 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + clocks = <&gmac_clk>, <&gmac_axi_clk>; + clock-names = "stmmaceth", "pclk"; + snps,pbl = <32>; + snps,fixed-burst; + snps,multicast-filter-bins = <64>; + snps,perfect-filter-entries = <32>; + snps,axi-config = <&gmac1_stmmac_axi_setup>; + thead,gmacapb = <&gmacapb_syscon1>; + status = "disabled"; + + mdio1: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + + gmac1_stmmac_axi_setup: stmmac-axi-config { + snps,wr_osr_lmt = <0xf>; + snps,rd_osr_lmt = <0xf>; + snps,blen = <0 0 64 32 0 0 0>; + }; + }; + uart0: serial@ffe7014000 { compatible = "snps,dw-apb-uart"; reg = <0xff 0xe7014000 0x0 0x100>; @@ -237,6 +305,17 @@ }; }; + + gmacapb_syscon0: syscon@ffec003000 { + compatible = "thead,th1520-gmacapb-syscon", "syscon"; + reg = <0xff 0xec003000 0x0 0x1000>; + }; + + gmacapb_syscon1: syscon@ffec004000 { + compatible = "thead,th1520-gmacapb-syscon", "syscon"; + reg = <0xff 0xec004000 0x0 0x1000>; + }; + gpio0: gpio@ffec005000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xec005000 0x0 0x1000>; From 6f5f0a51fb30b5950cc941d17777e140c06346f1 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 19 May 2023 02:45:36 +0800 Subject: [PATCH 15/52] dt-binding: riscv: add T-HEAD CPU reset The secondary CPUs in T-HEAD SMP capable platforms need some special handling. The first one is to write the warm reset entry to entry register. The second one is write a SoC specific control value to a SoC specific control reg. The last one is to clone some CSRs for secondary CPUs to ensure these CSRs' values are the same as the main boot CPU. This DT node is mainly used by opensbi firmware. Signed-off-by: Jisheng Zhang --- .../bindings/riscv/thead,cpu-reset.yaml | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/riscv/thead,cpu-reset.yaml diff --git a/Documentation/devicetree/bindings/riscv/thead,cpu-reset.yaml b/Documentation/devicetree/bindings/riscv/thead,cpu-reset.yaml new file mode 100644 index 00000000000000..ba8c87583b6bd0 --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/thead,cpu-reset.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/thead,cpu-reset.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD cpu reset controller + +maintainers: + - Jisheng Zhang + +description: | + The secondary CPUs in T-HEAD SMP capable platforms need some special + handling. The first one is to write the warm reset entry to entry + register. The second one is write a SoC specific control value to + a SoC specific control reg. The last one is to clone some CSRs for + secondary CPUs to ensure these CSRs' values are the same as the + main boot CPU. + +properties: + $nodename: + pattern: "^cpurst" + + compatible: + oneOf: + - description: CPU reset on T-HEAD TH1520 SoC + items: + - const: thead,reset-th1520 + + entry-reg: + $ref: /schemas/types.yaml#/definitions/uint64 + description: | + The entry reg address. + + entry-cnt: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The entry reg count. + + control-reg: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The control reg address. + + control-val: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The value to be set into the control reg. + + csr-copy: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: | + The CSR registers to be cloned during CPU warm reset. + +required: + - compatible + +additionalProperties: false + +examples: + - | + cpurst: cpurst@ffff019050 { + compatible = "thead,reset-th1520"; + entry-reg = <0xff 0xff019050>; + entry-cnt = <4>; + control-reg = <0xff 0xff015004>; + control-val = <0x1c>; + csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>; + }; From e0a861278f4e1423ed6cc15cc3c7851113179cc8 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Thu, 21 Sep 2023 16:47:50 +0800 Subject: [PATCH 16/52] [NFU] th1520: add cpu reset node from: https://lore.kernel.org/all/20230518184541.2627-7-jszhang@kernel.org/ + cpurst: cpurst { + compatible = "thead,reset-th1520"; -> "thead,reset-sample"; + entry-reg = <0xff 0xff019050>; + entry-cnt = <4>; + control-reg = <0xff 0xff015004>; + control-val = <0x1c>; + csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>; + }; + Signed-off-by: Han Gao --- arch/riscv/boot/dts/thead/th1520.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 146d40bbbfea53..b9239339e34c74 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -161,6 +161,15 @@ dma-noncoherent; ranges; + cpurst: cpurst { + compatible = "thead,reset-sample"; + entry-reg = <0xff 0xff019050>; + entry-cnt = <4>; + control-reg = <0xff 0xff015004>; + control-val = <0x1c>; + csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>; + }; + plic: interrupt-controller@ffd8000000 { compatible = "thead,th1520-plic", "thead,c900-plic"; reg = <0xff 0xd8000000 0x0 0x01000000>; From 02dc6fc82a204ee1d9ee593a7ffcf57cb20c1f3d Mon Sep 17 00:00:00 2001 From: Han Gao Date: Thu, 21 Sep 2023 15:02:53 +0800 Subject: [PATCH 17/52] [NFU] chore: remove compression for riscv Image Signed-off-by: Han Gao --- arch/riscv/Makefile | 2 +- scripts/package/builddeb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index b43a6bb7e4dcb6..ecf81ab9bd9e9a 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -152,7 +152,7 @@ ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy) KBUILD_IMAGE := $(boot)/loader.bin else ifeq ($(CONFIG_EFI_ZBOOT),) -KBUILD_IMAGE := $(boot)/Image.gz +KBUILD_IMAGE := $(boot)/Image else KBUILD_IMAGE := $(boot)/vmlinuz.efi endif diff --git a/scripts/package/builddeb b/scripts/package/builddeb index d7dd0d04c70c99..259668daea6376 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -85,7 +85,7 @@ install_linux_image () { case "${SRCARCH}" in um) installed_image_path="usr/bin/linux-${KERNELRELEASE}";; - parisc|mips|powerpc) + parisc|mips|powerpc|riscv*) installed_image_path="boot/vmlinux-${KERNELRELEASE}";; *) installed_image_path="boot/vmlinuz-${KERNELRELEASE}";; From 79114ed743325fb3262aa462f93f58ea2860d796 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Thu, 21 Sep 2023 18:54:59 +0800 Subject: [PATCH 18/52] [NFU] revyos: init defconfig Signed-off-by: Han Gao --- arch/riscv/configs/revyos_defconfig | 2545 +++++++++++++++++++++++++++ 1 file changed, 2545 insertions(+) create mode 100644 arch/riscv/configs/revyos_defconfig diff --git a/arch/riscv/configs/revyos_defconfig b/arch/riscv/configs/revyos_defconfig new file mode 100644 index 00000000000000..ee8c63d2383775 --- /dev/null +++ b/arch/riscv/configs/revyos_defconfig @@ -0,0 +1,2545 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ_FULL=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_JIT=y +CONFIG_BPF_LSM=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_NUMA_BALANCING=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_RDMA=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_MISC=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +# CONFIG_SYSFS_SYSCALL is not set +CONFIG_PROFILING=y +CONFIG_KEXEC=y +CONFIG_ARCH_THEAD=y +CONFIG_SMP=y +CONFIG_NUMA=y +# CONFIG_RISCV_ISA_SVNAPOT is not set +# CONFIG_RISCV_ISA_SVPBMT is not set +# CONFIG_RISCV_ISA_V is not set +# CONFIG_RISCV_ISA_ZBB is not set +# CONFIG_RISCV_ISA_ZICBOM is not set +# CONFIG_RISCV_ISA_ZICBOZ is not set +CONFIG_RISCV_SBI_V01=y +# CONFIG_RISCV_BOOT_SPINWAIT is not set +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +CONFIG_ENERGY_MODEL=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_RISCV_SBI_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPUFREQ_DT=m +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +# CONFIG_COMPAT_32BIT_TIME is not set +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_BLK_DEV_ZONED=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_WBT=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_BLK_SED_OPAL=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_KARMA_PARTITION=y +CONFIG_MQ_IOSCHED_KYBER=m +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y +CONFIG_Z3FOLD=m +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_KSM=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_DEFERRED_STRUCT_PAGE_INIT=y +CONFIG_USERFAULTFD=y +CONFIG_LRU_GEN=y +CONFIG_LRU_GEN_ENABLED=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=m +CONFIG_UNIX_DIAG=m +CONFIG_TLS=m +CONFIG_TLS_DEVICE=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_INTERFACE=m +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y +CONFIG_XDP_SOCKETS=y +CONFIG_XDP_SOCKETS_DIAG=m +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_FIB_TRIE_STATS=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_ESP_OFFLOAD=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_DIAG=m +CONFIG_INET_UDP_DIAG=m +CONFIG_INET_RAW_DIAG=m +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_NV=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_DCTCP=m +CONFIG_TCP_CONG_CDG=m +CONFIG_TCP_CONG_BBR=m +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_ESP_OFFLOAD=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_ILA=m +CONFIG_IPV6_VTI=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_GRE=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_IPV6_SEG6_LWTUNNEL=y +CONFIG_IPV6_SEG6_HMAC=y +CONFIG_NETLABEL=y +CONFIG_MPTCP=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_FLOW_OFFLOAD=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_FIB_INET=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m +CONFIG_NF_FLOW_TABLE_INET=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_SET=m +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPMARK=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_IPMAC=m +CONFIG_IP_SET_HASH_MAC=m +CONFIG_IP_SET_HASH_NETPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETNET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_FO=m +CONFIG_IP_VS_OVF=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_MH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_PE_SIP=m +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_LOG_ARP=m +CONFIG_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_SRH=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_CONNTRACK_BRIDGE=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_IP_DCCP=m +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y +CONFIG_SCTP_COOKIE_HMAC_MD5=y +CONFIG_RDS=m +CONFIG_RDS_TCP=m +CONFIG_TIPC=m +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_LLC2=m +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_PHONET=m +CONFIG_6LOWPAN=m +CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m +CONFIG_6LOWPAN_GHC_UDP=m +CONFIG_6LOWPAN_GHC_ICMPV6=m +CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m +CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m +CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m +CONFIG_IEEE802154=m +CONFIG_IEEE802154_6LOWPAN=m +CONFIG_MAC802154=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_CBS=m +CONFIG_NET_SCH_ETF=m +CONFIG_NET_SCH_TAPRIO=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_SKBPRIO=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=y +CONFIG_NET_SCH_CAKE=m +CONFIG_NET_SCH_FQ=m +CONFIG_NET_SCH_HHF=m +CONFIG_NET_SCH_PIE=m +CONFIG_NET_SCH_FQ_PIE=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_PLUG=m +CONFIG_NET_SCH_ETS=m +CONFIG_NET_SCH_DEFAULT=y +CONFIG_DEFAULT_FQ_CODEL=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=m +CONFIG_NET_CLS_BPF=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_CLS_MATCHALL=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_CANID=m +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_EMATCH_IPT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_SAMPLE=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_MPLS=m +CONFIG_NET_ACT_VLAN=m +CONFIG_NET_ACT_BPF=m +CONFIG_NET_ACT_CONNMARK=m +CONFIG_NET_ACT_CTINFO=m +CONFIG_NET_ACT_SKBMOD=m +CONFIG_NET_ACT_IFE=m +CONFIG_NET_ACT_TUNNEL_KEY=m +CONFIG_NET_ACT_CT=m +CONFIG_NET_ACT_GATE=m +CONFIG_NET_IFE_SKBMARK=m +CONFIG_NET_IFE_SKBPRIO=m +CONFIG_NET_IFE_SKBTCINDEX=m +CONFIG_DCB=y +CONFIG_BATMAN_ADV=m +CONFIG_BATMAN_ADV_NC=y +CONFIG_OPENVSWITCH=m +CONFIG_VSOCKETS=m +CONFIG_VIRTIO_VSOCKETS=m +CONFIG_NETLINK_DIAG=m +CONFIG_NET_MPLS_GSO=y +CONFIG_MPLS_ROUTING=m +CONFIG_MPLS_IPTUNNEL=m +CONFIG_HSR=m +CONFIG_NET_SWITCHDEV=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_BPF_STREAM_PARSER=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_DROP_MONITOR=m +CONFIG_HAMRADIO=y +CONFIG_AX25=m +CONFIG_NETROM=m +CONFIG_ROSE=m +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_YAM=m +CONFIG_CAN=m +CONFIG_CAN_J1939=m +CONFIG_CAN_ISOTP=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m +CONFIG_BT_HS=y +CONFIG_BT_6LOWPAN=m +CONFIG_BT_LEDS=y +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y +CONFIG_BT_HCIBTUSB_MTK=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_MRVL=m +CONFIG_BT_MRVL_SDIO=m +CONFIG_BT_ATH3K=m +CONFIG_BT_MTKUART=m +CONFIG_AF_RXRPC_IPV6=y +CONFIG_RXKAD=y +CONFIG_AF_KCM=m +CONFIG_CFG80211=m +CONFIG_MAC80211=m +CONFIG_MAC80211_MESH=y +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=y +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +CONFIG_NFC=m +CONFIG_NFC_DIGITAL=m +CONFIG_NFC_NCI=m +CONFIG_NFC_SIM=m +CONFIG_NFC_PORT100=m +CONFIG_NFC_PN533_USB=m +CONFIG_NFC_NXP_NCI=m +CONFIG_NFC_NXP_NCI_I2C=m +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +CONFIG_PCIEAER_INJECT=m +CONFIG_PCIE_DPC=y +CONFIG_PCIE_PTM=y +CONFIG_PCI_REALLOC_ENABLE_AUTO=y +CONFIG_PCI_STUB=m +CONFIG_PCI_PF_STUB=m +CONFIG_PCI_IOV=y +CONFIG_PCI_HOST_GENERIC=y +CONFIG_PCIE_MICROCHIP_HOST=y +CONFIG_PCIE_XILINX=y +CONFIG_PCIE_DW_PLAT_HOST=y +CONFIG_CXL_BUS=y +CONFIG_CXL_PCI=m +CONFIG_DEVTMPFS=y +CONFIG_FW_LOADER_COMPRESS=y +CONFIG_MHI_BUS_PCI_GENERIC=m +CONFIG_CONNECTOR=y +CONFIG_GOOGLE_FIRMWARE=y +CONFIG_GOOGLE_COREBOOT_TABLE=m +CONFIG_GOOGLE_MEMCONSOLE_COREBOOT=m +CONFIG_GOOGLE_VPD=m +CONFIG_EFI_BOOTLOADER_CONTROL=m +CONFIG_EFI_CAPSULE_LOADER=m +CONFIG_RESET_ATTACK_MITIGATION=y +CONFIG_GNSS=m +CONFIG_GNSS_SIRF_SERIAL=m +CONFIG_GNSS_UBX_SERIAL=m +CONFIG_MTD=m +CONFIG_MTD_AR7_PARTS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_MTD_OOPS=m +CONFIG_MTD_SWAP=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_SST25L=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_NAND_ECC_SW_BCH=y +CONFIG_MTD_LPDDR=m +CONFIG_MTD_SPI_NOR=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BLOCK=y +CONFIG_OF_OVERLAY=y +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_1284=y +CONFIG_BLK_DEV_NULL_BLK=m +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m +CONFIG_ZRAM=m +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_NVME=m +CONFIG_NVME_MULTIPATH=y +CONFIG_NVME_HWMON=y +CONFIG_NVME_FC=m +CONFIG_NVME_TCP=m +CONFIG_NVME_TARGET=m +CONFIG_NVME_TARGET_FC=m +CONFIG_NVME_TARGET_TCP=m +CONFIG_AD525X_DPOT=m +CONFIG_AD525X_DPOT_I2C=m +CONFIG_AD525X_DPOT_SPI=m +CONFIG_ICS932S401=m +CONFIG_ENCLOSURE_SERVICES=m +CONFIG_APDS9802ALS=m +CONFIG_ISL29003=m +CONFIG_ISL29020=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_BH1770=m +CONFIG_SENSORS_APDS990X=m +CONFIG_HMC6352=m +CONFIG_DS1682=m +CONFIG_C2PORT=m +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m +CONFIG_EEPROM_LEGACY=m +CONFIG_EEPROM_MAX6875=m +CONFIG_EEPROM_EE1004=m +CONFIG_SENSORS_LIS3_I2C=m +CONFIG_MISC_RTSX_PCI=m +CONFIG_MISC_RTSX_USB=m +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_ISCSI_TCP=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2X_FCOE=m +CONFIG_BE2ISCSI=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_HPSA=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_3W_SAS=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_MVSAS=m +# CONFIG_SCSI_MVSAS_DEBUG is not set +CONFIG_SCSI_MVUMI=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_ESAS2R=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_MPI3MR=m +CONFIG_SCSI_SMARTPQI=m +CONFIG_SCSI_HPTIOP=m +CONFIG_LIBFC=m +CONFIG_LIBFCOE=m +CONFIG_FCOE=m +CONFIG_SCSI_SNIC=m +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_QLA_FC=m +CONFIG_TCM_QLA2XXX=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_QEDI=m +CONFIG_QEDF=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_WD719X=m +CONFIG_SCSI_PMCRAID=m +CONFIG_SCSI_PM8001=m +CONFIG_SCSI_BFA_FC=m +CONFIG_SCSI_VIRTIO=m +CONFIG_SCSI_CHELSIO_FCOE=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_ATA=m +CONFIG_SATA_AHCI=m +CONFIG_SATA_MOBILE_LPM_POLICY=3 +CONFIG_SATA_AHCI_PLATFORM=m +CONFIG_AHCI_DWC=m +CONFIG_SATA_ACARD_AHCI=m +CONFIG_SATA_SIL24=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SX4=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATP867X=m +CONFIG_PATA_CMD64X=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_NINJA32=m +CONFIG_PATA_RDC=m +CONFIG_PATA_SCH=m +CONFIG_PATA_TOSHIBA=m +CONFIG_ATA_GENERIC=m +CONFIG_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_MD_CLUSTER=m +CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_UNSTRIPED=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_WRITECACHE=m +CONFIG_DM_ERA=m +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_DELAY=m +CONFIG_DM_UEVENT=y +CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m +CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y +CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_SWITCH=m +CONFIG_DM_LOG_WRITES=m +CONFIG_DM_INTEGRITY=m +CONFIG_DM_ZONED=m +CONFIG_TARGET_CORE=m +CONFIG_TCM_IBLOCK=m +CONFIG_TCM_FILEIO=m +CONFIG_TCM_PSCSI=m +CONFIG_TCM_USER2=m +CONFIG_LOOPBACK_TARGET=m +CONFIG_TCM_FC=m +CONFIG_ISCSI_TARGET=m +CONFIG_ISCSI_TARGET_CXGB4=m +CONFIG_SBP_TARGET=m +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_CTL=m +CONFIG_FIREWIRE=m +CONFIG_FIREWIRE_OHCI=m +CONFIG_FIREWIRE_SBP2=m +CONFIG_FIREWIRE_NET=m +CONFIG_FIREWIRE_NOSY=m +CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_WIREGUARD=m +CONFIG_EQUALIZER=m +CONFIG_IFB=m +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_BROADCAST=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_RANDOM=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_IPVTAP=m +CONFIG_VXLAN=m +CONFIG_GENEVE=m +CONFIG_GTP=m +CONFIG_MACSEC=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +CONFIG_NLMON=m +CONFIG_NET_VRF=m +CONFIG_VSOCKMON=m +CONFIG_MHI_NET=m +CONFIG_ATM_DUMMY=m +CONFIG_ATM_NICSTAR=m +CONFIG_ATM_NICSTAR_USE_SUNI=y +CONFIG_ATM_NICSTAR_USE_IDT77105=y +CONFIG_ATM_IA=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_SOLOS=m +CONFIG_ET131X=m +CONFIG_ACENIC=m +CONFIG_ENA_ETHERNET=m +CONFIG_PCNET32=m +CONFIG_AQTION=m +# CONFIG_NET_VENDOR_ARC is not set +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL1C=m +CONFIG_ALX=m +CONFIG_TIGON3=m +CONFIG_BNX2X=m +CONFIG_BNXT=m +CONFIG_BNXT_DCB=y +CONFIG_MACB=m +CONFIG_CAVIUM_PTP=m +CONFIG_LIQUIDIO=m +CONFIG_LIQUIDIO_VF=m +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T4_DCB=y +CONFIG_CHELSIO_T4_FCOE=y +CONFIG_CHELSIO_T4VF=m +CONFIG_ENIC=m +CONFIG_DL2K=m +CONFIG_BE2NET=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IGBVF=m +CONFIG_IXGBE=m +CONFIG_IXGBE_DCB=y +CONFIG_IXGBEVF=m +CONFIG_I40E=m +CONFIG_I40E_DCB=y +CONFIG_I40EVF=m +CONFIG_ICE=m +CONFIG_IGC=m +CONFIG_JME=m +CONFIG_SKGE=m +CONFIG_SKGE_GENESIS=y +CONFIG_SKY2=m +CONFIG_MLX4_EN=m +CONFIG_MLX5_CORE=m +CONFIG_MLX5_FPGA=y +CONFIG_MLX5_CORE_EN=y +CONFIG_MLX5_CORE_IPOIB=y +CONFIG_MLXFW=m +CONFIG_KSZ884X_PCI=m +CONFIG_LAN743X=m +CONFIG_MYRI10GE=m +CONFIG_NS83820=m +CONFIG_S2IO=m +CONFIG_NFP=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_QLA3XXX=m +CONFIG_QLCNIC=m +CONFIG_NETXEN_NIC=m +CONFIG_QED=m +CONFIG_QEDE=m +CONFIG_BNA=m +CONFIG_R6040=m +CONFIG_R8169=m +# CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SC92031=m +CONFIG_SIS190=m +CONFIG_SFC=m +CONFIG_SFC_FALCON=m +CONFIG_SFC_SIENA=m +CONFIG_SFC_SIENA_SRIOV=y +CONFIG_SMSC9420=m +CONFIG_STMMAC_ETH=y +CONFIG_DWMAC_DWC_QOS_ETH=m +CONFIG_DWMAC_GENERIC=m +CONFIG_DWMAC_THEAD=y +CONFIG_DWMAC_INTEL_PLAT=m +CONFIG_CASSINI=m +CONFIG_NIU=m +CONFIG_TEHUTI=m +CONFIG_TLAN=m +CONFIG_VIA_VELOCITY=m +CONFIG_LED_TRIGGER_PHY=y +CONFIG_SFP=m +CONFIG_AMD_PHY=m +CONFIG_AQUANTIA_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_BCM87XX_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_CORTINA_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_LXT_PHY=m +CONFIG_LSI_ET1011C_PHY=m +CONFIG_MARVELL_PHY=m +CONFIG_MARVELL_10G_PHY=m +CONFIG_MICREL_PHY=m +CONFIG_MICROCHIP_T1_PHY=m +CONFIG_MICROSEMI_PHY=m +CONFIG_NATIONAL_PHY=m +CONFIG_AT803X_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_RENESAS_PHY=m +CONFIG_ROCKCHIP_PHY=m +CONFIG_STE10XP=m +CONFIG_TERANETICS_PHY=m +CONFIG_DP83822_PHY=m +CONFIG_DP83TC811_PHY=m +CONFIG_DP83848_PHY=m +CONFIG_DP83867_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_CAN_VCAN=m +CONFIG_CAN_VXCAN=m +CONFIG_CAN_SLCAN=m +CONFIG_CAN_PEAK_PCIEFD=m +CONFIG_CAN_SJA1000=m +CONFIG_CAN_EMS_PCI=m +CONFIG_CAN_KVASER_PCI=m +CONFIG_CAN_PEAK_PCI=m +CONFIG_CAN_PLX_PCI=m +CONFIG_CAN_SJA1000_ISA=m +CONFIG_CAN_SOFTING=m +CONFIG_CAN_HI311X=m +CONFIG_CAN_MCP251X=m +CONFIG_CAN_MCP251XFD=m +CONFIG_CAN_8DEV_USB=m +CONFIG_CAN_EMS_USB=m +CONFIG_CAN_ESD_USB=m +CONFIG_CAN_GS_USB=m +CONFIG_CAN_KVASER_USB=m +CONFIG_CAN_MCBA_USB=m +CONFIG_CAN_PEAK_USB=m +CONFIG_CAN_UCAN=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_HUAWEI_CDC_NCM=m +CONFIG_USB_NET_CDC_MBIM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9700=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_HSO=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_CDC_PHONET=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_USB_NET_CH9200=m +CONFIG_USB_NET_AQC111=m +CONFIG_ADM8211=m +CONFIG_ATH5K=m +CONFIG_ATH9K=m +CONFIG_ATH9K_CHANNEL_CONTEXT=y +CONFIG_ATH9K_HTC=m +CONFIG_CARL9170=m +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m +CONFIG_AR5523=m +CONFIG_WIL6210=m +CONFIG_WIL6210_TRACING=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_USB=m +CONFIG_ATH11K=m +CONFIG_ATH11K_PCI=m +CONFIG_AT76C50X_USB=m +CONFIG_B43=m +CONFIG_B43_SDIO=y +CONFIG_B43LEGACY=m +CONFIG_BRCMSMAC=m +CONFIG_BRCMFMAC=m +# CONFIG_BRCMFMAC_SDIO is not set +CONFIG_BRCMFMAC_USB=y +CONFIG_BRCMFMAC_PCIE=y +CONFIG_AIRO=m +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IWL4965=m +CONFIG_IWL3945=m +CONFIG_IWLWIFI=m +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_MESH=y +CONFIG_LIBERTAS_THINFIRM=m +CONFIG_LIBERTAS_THINFIRM_USB=m +CONFIG_MWL8K=m +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x0E=m +CONFIG_MT76x2E=m +CONFIG_MT76x2U=m +CONFIG_MT7615E=m +CONFIG_MT7663U=m +CONFIG_MT7915E=m +CONFIG_MT7921E=m +CONFIG_MT7921U=m +CONFIG_RT2X00=m +CONFIG_RT2400PCI=m +CONFIG_RT2500PCI=m +CONFIG_RT61PCI=m +CONFIG_RT2800PCI=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RTL8180=m +CONFIG_RTL8187=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8723BE=m +CONFIG_RTL8188EE=m +CONFIG_RTL8192EE=m +CONFIG_RTL8821AE=m +CONFIG_RTL8192CU=m +# CONFIG_RTLWIFI_DEBUG is not set +CONFIG_RTL8XXXU=m +CONFIG_RTW88=m +CONFIG_RTW88_8822BE=m +CONFIG_RTW88_8822BS=m +CONFIG_RTW88_8822BU=m +CONFIG_RTW88_8822CE=m +CONFIG_RTW88_8822CS=m +CONFIG_RTW88_8822CU=m +CONFIG_RTW88_8723DE=m +CONFIG_RTW88_8723DU=m +CONFIG_RTW88_8821CE=m +CONFIG_RTW88_8821CS=m +CONFIG_RTW88_8821CU=m +CONFIG_RTW89=m +CONFIG_RTW89_8852AE=m +CONFIG_RTW89_8852BE=m +CONFIG_RTW89_8852CE=m +CONFIG_RSI_91X=m +# CONFIG_RSI_SDIO is not set +# CONFIG_WLAN_VENDOR_TI is not set +CONFIG_ZD1211RW=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_MAC80211_HWSIM=m +CONFIG_IEEE802154_FAKELB=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m +CONFIG_IEEE802154_ATUSB=m +CONFIG_IEEE802154_ADF7242=m +CONFIG_IEEE802154_HWSIM=m +CONFIG_WWAN=m +CONFIG_MHI_WWAN_CTRL=m +CONFIG_MHI_WWAN_MBIM=m +CONFIG_IOSM=m +CONFIG_INPUT_SPARSEKMAP=m +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_KEYBOARD_ADP5588=m +CONFIG_KEYBOARD_QT2160=m +CONFIG_KEYBOARD_LM8323=m +CONFIG_KEYBOARD_MAX7359=m +CONFIG_KEYBOARD_OPENCORES=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_SENTELIC=y +CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=m +CONFIG_JOYSTICK_IFORCE_232=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_ZHENHUA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_WALKERA0701=m +CONFIG_JOYSTICK_PXRC=m +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_HANWANG=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_PEGASUS=m +CONFIG_TABLET_SERIAL_WACOM4=m +CONFIG_RMI4_F34=y +CONFIG_RMI4_F3A=y +CONFIG_RMI4_F55=y +CONFIG_SERIO_ALTERA_PS2=m +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LEGACY_TIOCSTI is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_EXAR=m +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_SIFIVE=y +CONFIG_SERIAL_SIFIVE_CONSOLE=y +CONFIG_SERIAL_RP2=m +CONFIG_N_GSM=m +CONFIG_NOZOMI=m +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=m +CONFIG_VIRTIO_CONSOLE=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_TCG_TIS_SPI=m +CONFIG_TCG_VTPM_PROXY=m +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_ISCH=m +CONFIG_I2C_DESIGNWARE_PLATFORM=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PCA_PLATFORM=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_DIOLAN_U2C=m +CONFIG_I2C_ROBOTFUZZ_OSIF=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIPERBOARD=m +CONFIG_SPI=y +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_CADENCE_QUADSPI=m +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_SIFIVE=m +CONFIG_SPI_SPIDEV=y +CONFIG_PPS_CLIENT_LDISC=m +CONFIG_PPS_CLIENT_PARPORT=m +CONFIG_DP83640_PHY=m +CONFIG_PTP_1588_CLOCK_INES=m +CONFIG_PTP_1588_CLOCK_IDT82P33=m +CONFIG_PTP_1588_CLOCK_IDTCM=m +CONFIG_PTP_1588_CLOCK_OCP=m +CONFIG_PINCTRL=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_EXAR=m +CONFIG_GPIO_SIFIVE=y +CONFIG_GPIO_PCI_IDIO_16=m +CONFIG_GPIO_PCIE_IDIO_24=m +CONFIG_GPIO_VIPERBOARD=m +CONFIG_W1=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_GPIO=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2405=m +CONFIG_W1_SLAVE_DS2408=m +CONFIG_W1_SLAVE_DS2413=m +CONFIG_W1_SLAVE_DS2406=m +CONFIG_W1_SLAVE_DS2423=m +CONFIG_W1_SLAVE_DS2805=m +CONFIG_W1_SLAVE_DS2431=m +CONFIG_W1_SLAVE_DS2433=m +CONFIG_W1_SLAVE_DS2438=m +CONFIG_W1_SLAVE_DS2780=m +CONFIG_W1_SLAVE_DS2781=m +CONFIG_W1_SLAVE_DS28E04=m +CONFIG_W1_SLAVE_DS28E17=m +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_RESTART=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_BQ27XXX=m +# CONFIG_BATTERY_BQ27XXX_I2C is not set +CONFIG_SENSORS_AD7414=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7411=m +CONFIG_SENSORS_ADT7462=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ADT7475=m +CONFIG_SENSORS_ASC7621=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DRIVETEMP=m +CONFIG_SENSORS_DS620=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FTSTEUTATES=m +CONFIG_SENSORS_G760A=m +CONFIG_SENSORS_JC42=m +CONFIG_SENSORS_LINEAGE=m +CONFIG_SENSORS_LTC4151=m +CONFIG_SENSORS_LTC4215=m +CONFIG_SENSORS_LTC4245=m +CONFIG_SENSORS_LTC4261=m +CONFIG_SENSORS_MAX1111=m +CONFIG_SENSORS_MAX16065=m +CONFIG_SENSORS_MAX1668=m +CONFIG_SENSORS_MAX6639=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_ADCXX=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM73=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_LM95241=m +CONFIG_SENSORS_LM95245=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_NTC_THERMISTOR=m +CONFIG_SENSORS_NCT6683=m +CONFIG_SENSORS_NCT6775=m +CONFIG_SENSORS_NCT7802=m +CONFIG_SENSORS_NCT7904=m +CONFIG_SENSORS_NPCM7XX=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_SHT3x=m +CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_EMC1403=m +CONFIG_SENSORS_EMC2103=m +CONFIG_SENSORS_EMC6W201=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SCH5627=m +CONFIG_SENSORS_ADS7828=m +CONFIG_SENSORS_ADS7871=m +CONFIG_SENSORS_AMC6821=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TMP102=m +CONFIG_SENSORS_TMP401=m +CONFIG_SENSORS_TMP421=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83773G=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83795=m +CONFIG_SENSORS_W83L786NG=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_THERMAL_STATISTICS=y +CONFIG_THERMAL_GOV_FAIR_SHARE=y +CONFIG_THERMAL_GOV_BANG_BANG=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV=y +CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP=y +CONFIG_SOFT_WATCHDOG=m +CONFIG_DA9063_WATCHDOG=m +CONFIG_MFD_AXP20X_I2C=m +CONFIG_MFD_DA9063=m +CONFIG_MFD_VIPERBOARD=m +CONFIG_MFD_TPS65086=m +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=m +CONFIG_REGULATOR_AXP20X=m +CONFIG_REGULATOR_DA9063=m +CONFIG_REGULATOR_TPS65086=m +CONFIG_RC_CORE=m +CONFIG_LIRC=y +CONFIG_RC_DECODERS=y +CONFIG_IR_IMON_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m +CONFIG_RC_DEVICES=y +CONFIG_IR_IGORPLUGUSB=m +CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_IMON_RAW=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_TTUSBIR=m +CONFIG_RC_ATI_REMOTE=m +CONFIG_RC_LOOPBACK=m +CONFIG_MEDIA_CEC_RC=y +CONFIG_USB_PULSE8_CEC=m +CONFIG_USB_RAINSHADOW_CEC=m +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_GSPCA=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_DTCS033=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_KONICA=m +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_MR97310A=m +CONFIG_USB_GSPCA_NW80X=m +CONFIG_USB_GSPCA_OV519=m +CONFIG_USB_GSPCA_OV534=m +CONFIG_USB_GSPCA_OV534_9=m +CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7302=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SE401=m +CONFIG_USB_GSPCA_SN9C2028=m +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m +CONFIG_USB_GSPCA_SPCA1528=m +CONFIG_USB_GSPCA_SPCA500=m +CONFIG_USB_GSPCA_SPCA501=m +CONFIG_USB_GSPCA_SPCA505=m +CONFIG_USB_GSPCA_SPCA506=m +CONFIG_USB_GSPCA_SPCA508=m +CONFIG_USB_GSPCA_SPCA561=m +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STK1135=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m +CONFIG_USB_GSPCA_TOUPTEK=m +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_XIRLINK_CIT=m +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_USB_GL860=m +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_PWC=m +CONFIG_USB_S2255=m +CONFIG_VIDEO_USBTV=m +CONFIG_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_STK1160=m +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_RC=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_ALSA=m +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_DVB_AS102=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_DVBSKY=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_ZD1301=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_SMS_USB_DRV=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_USB_AIRSPY=m +CONFIG_USB_HACKRF=m +CONFIG_USB_MSI2500=m +CONFIG_MEDIA_PCI_SUPPORT=y +CONFIG_VIDEO_SOLO6X10=m +CONFIG_VIDEO_TW5864=m +CONFIG_VIDEO_TW68=m +CONFIG_VIDEO_TW686X=m +CONFIG_VIDEO_DT3155=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_IVTV_ALSA=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_BT848=m +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX18_ALSA=m +CONFIG_VIDEO_CX23885=m +CONFIG_MEDIA_ALTERA_CI=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7164=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_DDBRIDGE=m +CONFIG_DVB_DM1105=m +CONFIG_MANTIS_CORE=m +CONFIG_DVB_MANTIS=m +CONFIG_DVB_HOPPER=m +CONFIG_DVB_NETUP_UNIDVB=m +CONFIG_DVB_NGENE=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_PT1=m +CONFIG_DVB_PT3=m +CONFIG_DVB_SMIPCIE=m +CONFIG_DVB_BUDGET_CORE=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m +CONFIG_USB_KEENE=m +CONFIG_USB_MA901=m +CONFIG_USB_MR800=m +CONFIG_USB_RAREMONO=m +CONFIG_RADIO_SI470X=m +CONFIG_USB_SI470X=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_SMS_SDIO_DRV=m +CONFIG_V4L_TEST_DRIVERS=y +CONFIG_VIDEO_VIVID=m +CONFIG_VIDEO_VIVID_CEC=y +CONFIG_DVB_FIREDTV=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +CONFIG_VIDEO_SAA7185=m +CONFIG_DVB_DUMMY_FE=m +CONFIG_DRM=m +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_DP_AUX_CHARDEV=y +CONFIG_DRM_RADEON=m +CONFIG_DRM_AMDGPU=m +CONFIG_DRM_AMDGPU_SI=y +CONFIG_DRM_AMDGPU_CIK=y +CONFIG_DRM_AMDGPU_USERPTR=y +CONFIG_DRM_AMD_DC_SI=y +CONFIG_DRM_VGEM=m +CONFIG_DRM_UDL=m +CONFIG_DRM_QXL=m +CONFIG_DRM_VIRTIO_GPU=m +CONFIG_DRM_BOCHS=m +CONFIG_DRM_CIRRUS_QEMU=m +CONFIG_FB=y +CONFIG_FB_S3=m +CONFIG_FB_3DFX=m +CONFIG_FB_VT8623=m +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_SMSCUFX=m +CONFIG_FB_UDL=m +CONFIG_FB_MB862XX=m +CONFIG_FIRMWARE_EDID=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=m +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_SOUND=m +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +CONFIG_SND=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_ALOOP=m +CONFIG_SND_MTS64=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AD1889=m +CONFIG_SND_OXYGEN=m +CONFIG_SND_CTXFI=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIOX=m +CONFIG_SND_INDIGODJX=m +CONFIG_SND_HDSPM=m +CONFIG_SND_LOLA=m +CONFIG_SND_LX6464ES=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_VIRTUOSO=m +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_PATCH_LOADER=y +CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_ANALOG=m +CONFIG_SND_HDA_CODEC_SIGMATEL=m +CONFIG_SND_HDA_CODEC_VIA=m +CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_HDA_CODEC_CIRRUS=m +CONFIG_SND_HDA_CODEC_CS8409=m +CONFIG_SND_HDA_CODEC_CONEXANT=m +CONFIG_SND_HDA_CODEC_CA0110=m +CONFIG_SND_HDA_CODEC_CA0132=m +CONFIG_SND_HDA_CODEC_CMEDIA=m +CONFIG_SND_HDA_CODEC_SI3054=m +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=1 +CONFIG_SND_HDA_PREALLOC_SIZE=2048 +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_USB_HIFACE=m +CONFIG_SND_BCD2000=m +CONFIG_SND_USB_POD=m +CONFIG_SND_USB_PODHD=m +CONFIG_SND_USB_TONEPORT=m +CONFIG_SND_USB_VARIAX=m +CONFIG_SND_DICE=m +CONFIG_SND_OXFW=m +CONFIG_SND_ISIGHT=m +CONFIG_SND_FIREWORKS=m +CONFIG_SND_BEBOB=m +CONFIG_SND_FIREWIRE_DIGI00X=m +CONFIG_SND_FIREWIRE_TASCAM=m +CONFIG_SND_FIREWIRE_MOTU=m +CONFIG_SND_FIREFACE=m +CONFIG_SND_SOC=m +CONFIG_SND_SOC_MAX98373_SDW=m +CONFIG_SND_SOC_RT1308_SDW=m +CONFIG_SND_SOC_RT5682_SDW=m +CONFIG_SND_SOC_RT700_SDW=m +CONFIG_SND_SOC_RT711_SDW=m +CONFIG_SND_SOC_RT715_SDW=m +CONFIG_HID=m +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_A4TECH=m +CONFIG_HID_ACCUTOUCH=m +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=m +CONFIG_HID_ASUS=m +CONFIG_HID_AUREAL=m +CONFIG_HID_BELKIN=m +CONFIG_HID_BETOP_FF=m +CONFIG_HID_BIGBEN_FF=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_CORSAIR=m +CONFIG_HID_COUGAR=m +CONFIG_HID_MACALLY=m +CONFIG_HID_PRODIKEYS=m +CONFIG_HID_CMEDIA=m +CONFIG_HID_CP2112=m +CONFIG_HID_CREATIVE_SB0540=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=m +CONFIG_HID_ELAN=m +CONFIG_HID_ELECOM=m +CONFIG_HID_ELO=m +CONFIG_HID_EZKEY=m +CONFIG_HID_FT260=m +CONFIG_HID_GEMBIRD=m +CONFIG_HID_GFRM=m +CONFIG_HID_GLORIOUS=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_VIVALDI=m +CONFIG_HID_GT683R=m +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_KYE=m +CONFIG_HID_UCLOGIC=m +CONFIG_HID_WALTOP=m +CONFIG_HID_VIEWSONIC=m +CONFIG_HID_GYRATION=m +CONFIG_HID_ICADE=m +CONFIG_HID_ITE=m +CONFIG_HID_JABRA=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=m +CONFIG_HID_MALTRON=m +CONFIG_HID_MAYFLASH=m +CONFIG_HID_REDRAGON=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_NINTENDO=m +CONFIG_NINTENDO_FF=y +CONFIG_HID_NTI=m +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PENMOUNT=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m +CONFIG_HID_PICOLCD_FB=y +CONFIG_HID_PICOLCD_BACKLIGHT=y +CONFIG_HID_PICOLCD_LEDS=y +CONFIG_HID_PICOLCD_CIR=y +CONFIG_HID_PLANTRONICS=m +CONFIG_HID_PLAYSTATION=m +CONFIG_PLAYSTATION_FF=y +CONFIG_HID_PRIMAX=m +CONFIG_HID_RETRODE=m +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAITEK=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SEMITEK=m +CONFIG_HID_SONY=m +CONFIG_SONY_FF=y +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_STEAM=m +CONFIG_HID_STEELSERIES=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_RMI=m +CONFIG_HID_GREENASIA=m +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THINGM=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_UDRAW_PS3=m +CONFIG_HID_U2FZERO=m +CONFIG_HID_WACOM=m +CONFIG_HID_WIIMOTE=m +CONFIG_HID_XINMO=m +CONFIG_HID_ZEROPLUS=m +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=m +CONFIG_HID_SENSOR_HUB=m +CONFIG_HID_SENSOR_CUSTOM_SENSOR=m +CONFIG_HID_ALPS=m +CONFIG_HID_MCP2221=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_LED_TRIG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_LEDS_TRIGGER_USBPORT=m +CONFIG_USB_MON=m +CONFIG_USB_XHCI_HCD=m +CONFIG_USB_XHCI_PLATFORM=m +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_HCD_PLATFORM=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_PLATFORM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_TMC=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_REALTEK=m +CONFIG_USB_STORAGE_DATAFAB=m +CONFIG_USB_STORAGE_FREECOM=m +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_USBAT=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +CONFIG_USB_STORAGE_ALAUDA=m +CONFIG_USB_STORAGE_ONETOUCH=m +CONFIG_USB_STORAGE_KARMA=m +CONFIG_USB_STORAGE_CYPRESS_ATACB=m +CONFIG_USB_STORAGE_ENE_UB6250=m +CONFIG_USB_UAS=m +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_VHCI_HC_PORTS=15 +CONFIG_USBIP_VHCI_NR_HCS=8 +CONFIG_USBIP_HOST=m +CONFIG_USB_MUSB_HDRC=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m +CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7715_PARPORT=y +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_QCAUX=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SYMBOL=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTICON=m +CONFIG_USB_SERIAL_XSENS_MT=m +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m +CONFIG_USB_SERIAL_UPD78F0730=m +CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_SEVSEG=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_APPLE_MFI_FASTCHARGE=m +CONFIG_USB_SISUSBVGA=m +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_TEST=m +CONFIG_USB_EHSET_TEST_FIXTURE=m +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_YUREX=m +CONFIG_USB_CHAOSKEY=m +CONFIG_NOP_USB_XCEIV=m +CONFIG_MMC=y +CONFIG_PWRSEQ_EMMC=m +CONFIG_PWRSEQ_SIMPLE=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_MINORS=256 +CONFIG_SDIO_UART=m +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +CONFIG_MMC_SDHCI_OF_AT91=y +CONFIG_MMC_SDHCI_OF_DWCMSHC=y +CONFIG_MMC_SDHCI_CADENCE=y +CONFIG_MMC_TIFM_SD=m +CONFIG_MMC_SPI=m +CONFIG_MMC_CB710=m +CONFIG_MMC_VIA_SDMMC=m +CONFIG_MMC_DW=m +CONFIG_MMC_VUB300=m +CONFIG_MMC_USHC=m +CONFIG_MMC_REALTEK_PCI=m +CONFIG_MMC_REALTEK_USB=m +CONFIG_MMC_TOSHIBA_PCI=m +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_GPIO=m +CONFIG_LEDS_LP3944=m +CONFIG_LEDS_PCA955X=m +CONFIG_LEDS_DAC124S085=m +CONFIG_LEDS_REGULATOR=m +CONFIG_LEDS_BD2802=m +CONFIG_LEDS_LT3593=m +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LEDS_TRIGGER_MTD=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_BACKLIGHT=m +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_ACTIVITY=m +CONFIG_LEDS_TRIGGER_DEFAULT_ON=m +CONFIG_LEDS_TRIGGER_TRANSIENT=m +CONFIG_LEDS_TRIGGER_CAMERA=m +CONFIG_LEDS_TRIGGER_PANIC=y +CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m +CONFIG_ACCESSIBILITY=y +CONFIG_A11Y_BRAILLE_CONSOLE=y +CONFIG_SPEAKUP=m +CONFIG_SPEAKUP_SYNTH_ACNTSA=m +CONFIG_SPEAKUP_SYNTH_APOLLO=m +CONFIG_SPEAKUP_SYNTH_AUDPTR=m +CONFIG_SPEAKUP_SYNTH_BNS=m +CONFIG_SPEAKUP_SYNTH_DECTLK=m +CONFIG_SPEAKUP_SYNTH_DECEXT=m +CONFIG_SPEAKUP_SYNTH_LTLK=m +CONFIG_SPEAKUP_SYNTH_SOFT=m +CONFIG_SPEAKUP_SYNTH_SPKOUT=m +CONFIG_SPEAKUP_SYNTH_TXPRT=m +CONFIG_SPEAKUP_SYNTH_DUMMY=m +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_PCF85063=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_DA9063=m +CONFIG_RTC_DRV_GOLDFISH=y +CONFIG_DMADEVICES=y +CONFIG_ASYNC_TX_DMA=y +CONFIG_UIO_CIF=m +CONFIG_UIO_AEC=m +CONFIG_UIO_SERCOS3=m +CONFIG_UIO_PCI_GENERIC=m +CONFIG_UIO_NETX=m +CONFIG_UIO_MF624=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_PMEM=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=m +CONFIG_VHOST_NET=m +CONFIG_VHOST_SCSI=m +CONFIG_VHOST_VSOCK=m +CONFIG_STAGING=y +CONFIG_RTL8723BS=m +CONFIG_R8712U=m +CONFIG_QLGE=m +CONFIG_GOLDFISH=y +CONFIG_MAILBOX=y +CONFIG_SOUNDWIRE=m +CONFIG_SOUNDWIRE_QCOM=m +CONFIG_MEMORY=y +CONFIG_ADIS16201=m +CONFIG_ADIS16209=m +CONFIG_ADXL345_I2C=m +CONFIG_ADXL345_SPI=m +CONFIG_ADXL372_SPI=m +CONFIG_ADXL372_I2C=m +CONFIG_BMA180=m +CONFIG_BMA220=m +CONFIG_BMA400=m +CONFIG_BMC150_ACCEL=m +CONFIG_DA280=m +CONFIG_DA311=m +CONFIG_DMARD09=m +CONFIG_DMARD10=m +CONFIG_HID_SENSOR_ACCEL_3D=m +CONFIG_IIO_ST_ACCEL_3AXIS=m +CONFIG_KXSD9=m +CONFIG_KXCJK1013=m +CONFIG_MC3230=m +CONFIG_MMA7455_I2C=m +CONFIG_MMA7455_SPI=m +CONFIG_MMA7660=m +CONFIG_MMA8452=m +CONFIG_MMA9551=m +CONFIG_MMA9553=m +CONFIG_MXC4005=m +CONFIG_MXC6255=m +CONFIG_SCA3000=m +CONFIG_STK8312=m +CONFIG_STK8BA50=m +CONFIG_AD7091R5=m +CONFIG_AD7124=m +CONFIG_AD7192=m +CONFIG_AD7266=m +CONFIG_AD7291=m +CONFIG_AD7292=m +CONFIG_AD7298=m +CONFIG_AD7476=m +CONFIG_AD7606_IFACE_PARALLEL=m +CONFIG_AD7606_IFACE_SPI=m +CONFIG_AD7766=m +CONFIG_AD7768_1=m +CONFIG_AD7780=m +CONFIG_AD7791=m +CONFIG_AD7793=m +CONFIG_AD7887=m +CONFIG_AD7923=m +CONFIG_AD7949=m +CONFIG_AD799X=m +CONFIG_AD9467=m +CONFIG_ADI_AXI_ADC=m +CONFIG_AXP20X_ADC=m +CONFIG_AXP288_ADC=m +CONFIG_CC10001_ADC=m +CONFIG_HI8435=m +CONFIG_HX711=m +CONFIG_INA2XX_ADC=m +CONFIG_LTC2471=m +CONFIG_LTC2485=m +CONFIG_LTC2496=m +CONFIG_LTC2497=m +CONFIG_MAX1027=m +CONFIG_MAX11100=m +CONFIG_MAX1118=m +CONFIG_MAX1241=m +CONFIG_MAX1363=m +CONFIG_MAX9611=m +CONFIG_MCP320X=m +CONFIG_MCP3422=m +CONFIG_MCP3911=m +CONFIG_NAU7802=m +CONFIG_TI_ADC081C=m +CONFIG_TI_ADC0832=m +CONFIG_TI_ADC084S021=m +CONFIG_TI_ADC12138=m +CONFIG_TI_ADC108S102=m +CONFIG_TI_ADC128S052=m +CONFIG_TI_ADC161S626=m +CONFIG_TI_ADS1015=m +CONFIG_TI_ADS7950=m +CONFIG_VIPERBOARD_ADC=m +CONFIG_AD5064=m +CONFIG_AD5360=m +CONFIG_AD5380=m +CONFIG_AD5421=m +CONFIG_AD5446=m +CONFIG_AD5449=m +CONFIG_AD5592R=m +CONFIG_AD5593R=m +CONFIG_AD5504=m +CONFIG_AD5624R_SPI=m +CONFIG_AD5686_SPI=m +CONFIG_AD5696_I2C=m +CONFIG_AD5755=m +CONFIG_AD5758=m +CONFIG_AD5761=m +CONFIG_AD5764=m +CONFIG_AD5770R=m +CONFIG_AD5791=m +CONFIG_AD7303=m +CONFIG_AD8801=m +CONFIG_DS4424=m +CONFIG_LTC1660=m +CONFIG_LTC2632=m +CONFIG_M62332=m +CONFIG_MAX517=m +CONFIG_MCP4725=m +CONFIG_MCP4922=m +CONFIG_TI_DAC082S085=m +CONFIG_TI_DAC5571=m +CONFIG_TI_DAC7311=m +CONFIG_TI_DAC7612=m +CONFIG_ADIS16080=m +CONFIG_ADIS16130=m +CONFIG_ADIS16136=m +CONFIG_ADIS16260=m +CONFIG_ADXRS290=m +CONFIG_ADXRS450=m +CONFIG_BMG160=m +CONFIG_FXAS21002C=m +CONFIG_HID_SENSOR_GYRO_3D=m +CONFIG_MPU3050_I2C=m +CONFIG_IIO_ST_GYRO_3AXIS=m +CONFIG_ITG3200=m +CONFIG_ADIS16460=m +CONFIG_ADIS16475=m +CONFIG_ADIS16480=m +CONFIG_BMI160_I2C=m +CONFIG_BMI160_SPI=m +CONFIG_FXOS8700_I2C=m +CONFIG_FXOS8700_SPI=m +CONFIG_KMX61=m +CONFIG_INV_ICM42600_I2C=m +CONFIG_INV_ICM42600_SPI=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_INV_MPU6050_SPI=m +CONFIG_IIO_ST_LSM6DSX=m +CONFIG_ADJD_S311=m +CONFIG_ADUX1020=m +CONFIG_AL3010=m +CONFIG_AL3320A=m +CONFIG_APDS9300=m +CONFIG_APDS9960=m +CONFIG_AS73211=m +CONFIG_BH1750=m +CONFIG_BH1780=m +CONFIG_CM32181=m +CONFIG_CM3232=m +CONFIG_CM3323=m +CONFIG_CM36651=m +CONFIG_GP2AP002=m +CONFIG_GP2AP020A00F=m +CONFIG_SENSORS_ISL29018=m +CONFIG_SENSORS_ISL29028=m +CONFIG_ISL29125=m +CONFIG_HID_SENSOR_ALS=m +CONFIG_HID_SENSOR_PROX=m +CONFIG_JSA1212=m +CONFIG_RPR0521=m +CONFIG_LTR501=m +CONFIG_LV0104CS=m +CONFIG_MAX44000=m +CONFIG_MAX44009=m +CONFIG_NOA1305=m +CONFIG_OPT3001=m +CONFIG_PA12203001=m +CONFIG_SI1133=m +CONFIG_SI1145=m +CONFIG_STK3310=m +CONFIG_ST_UVIS25=m +CONFIG_TCS3414=m +CONFIG_TCS3472=m +CONFIG_SENSORS_TSL2563=m +CONFIG_TSL2583=m +CONFIG_TSL2772=m +CONFIG_TSL4531=m +CONFIG_US5182D=m +CONFIG_VCNL4000=m +CONFIG_VCNL4035=m +CONFIG_VEML6030=m +CONFIG_VEML6070=m +CONFIG_VL6180=m +CONFIG_ZOPT2201=m +CONFIG_AK09911=m +CONFIG_BMC150_MAGN_I2C=m +CONFIG_BMC150_MAGN_SPI=m +CONFIG_MAG3110=m +CONFIG_HID_SENSOR_MAGNETOMETER_3D=m +CONFIG_MMC35240=m +CONFIG_IIO_ST_MAGN_3AXIS=m +CONFIG_SENSORS_HMC5843_I2C=m +CONFIG_SENSORS_HMC5843_SPI=m +CONFIG_SENSORS_RM3100_I2C=m +CONFIG_SENSORS_RM3100_SPI=m +CONFIG_HID_SENSOR_INCLINOMETER_3D=m +CONFIG_HID_SENSOR_DEVICE_ROTATION=m +CONFIG_ABP060MG=m +CONFIG_BMP280=m +CONFIG_DLHL60D=m +CONFIG_DPS310=m +CONFIG_HID_SENSOR_PRESS=m +CONFIG_HP03=m +CONFIG_ICP10100=m +CONFIG_MPL115_I2C=m +CONFIG_MPL115_SPI=m +CONFIG_MPL3115=m +CONFIG_MS5611=m +CONFIG_MS5637=m +CONFIG_IIO_ST_PRESS=m +CONFIG_T5403=m +CONFIG_HP206C=m +CONFIG_ZPA2326=m +CONFIG_ISL29501=m +CONFIG_LIDAR_LITE_V2=m +CONFIG_MB1232=m +CONFIG_PING=m +CONFIG_RFD77402=m +CONFIG_SRF04=m +CONFIG_SX9310=m +CONFIG_SRF08=m +CONFIG_VCNL3020=m +CONFIG_VL53L0X_I2C=m +CONFIG_LTC2983=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_HID_SENSOR_TEMP=m +CONFIG_MLX90614=m +CONFIG_MLX90632=m +CONFIG_TMP006=m +CONFIG_TMP007=m +CONFIG_TSYS01=m +CONFIG_TSYS02D=m +CONFIG_MAX31856=m +CONFIG_PWM=y +CONFIG_PWM_SIFIVE=m +CONFIG_RESET_SIMPLE=y +CONFIG_LIBNVDIMM=m +CONFIG_DEV_DAX=m +CONFIG_EXT4_FS=m +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y +CONFIG_OCFS2_FS=m +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_NILFS2_FS=m +CONFIG_F2FS_FS=m +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_COMPRESSION=y +CONFIG_ZONEFS_FS=m +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_AUTOFS_FS=m +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_VIRTIO_FS=m +CONFIG_OVERLAY_FS=m +CONFIG_FSCACHE=m +CONFIG_FSCACHE_STATS=y +CONFIG_CACHEFILES=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_EXFAT_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_INODE64=y +CONFIG_HUGETLBFS=y +CONFIG_ORANGEFS_FS=m +CONFIG_ADFS_FS=m +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_UBIFS_FS=m +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=y +CONFIG_VXFS_FS=m +CONFIG_MINIX_FS=m +CONFIG_OMFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_QNX6FS_FS=m +CONFIG_ROMFS_FS=m +CONFIG_ROMFS_BACKED_BY_BOTH=y +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_EROFS_FS=m +CONFIG_NFS_FS=m +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=m +CONFIG_NFS_SWAP=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_NFS_FSCACHE=y +# CONFIG_NFS_V4_2_READ_PLUS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_BLOCKLAYOUT=y +CONFIG_NFSD_V4_SECURITY_LABEL=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_CEPH_FS=m +CONFIG_CEPH_FSCACHE=y +CONFIG_CEPH_FS_POSIX_ACL=y +CONFIG_CIFS=m +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_FSCACHE=y +CONFIG_SMB_SERVER=m +CONFIG_CODA_FS=m +CONFIG_AFS_FS=m +CONFIG_AFS_FSCACHE=y +CONFIG_9P_FS=m +CONFIG_9P_FSCACHE=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_MAC_ROMAN=m +CONFIG_NLS_MAC_CELTIC=m +CONFIG_NLS_MAC_CENTEURO=m +CONFIG_NLS_MAC_CROATIAN=m +CONFIG_NLS_MAC_CYRILLIC=m +CONFIG_NLS_MAC_GAELIC=m +CONFIG_NLS_MAC_GREEK=m +CONFIG_NLS_MAC_ICELAND=m +CONFIG_NLS_MAC_INUIT=m +CONFIG_NLS_MAC_ROMANIAN=m +CONFIG_NLS_MAC_TURKISH=m +CONFIG_DLM=m +CONFIG_DLM_DEBUG=y +CONFIG_UNICODE=y +CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_KEY_DH_OPERATIONS=y +CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK_XFRM=y +CONFIG_LSM_MMAP_MIN_ADDR=32768 +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_TOMOYO=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_YAMA=y +CONFIG_SECURITY_LANDLOCK=y +CONFIG_INTEGRITY_SIGNATURE=y +CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y +# CONFIG_INTEGRITY_TRUSTED_KEYRING is not set +CONFIG_INTEGRITY_PLATFORM_KEYRING=y +CONFIG_INTEGRITY_MACHINE_KEYRING=y +CONFIG_IMA=y +CONFIG_IMA_SIG_TEMPLATE=y +CONFIG_IMA_DEFAULT_HASH_SHA256=y +CONFIG_IMA_APPRAISE=y +CONFIG_IMA_ARCH_POLICY=y +CONFIG_EVM=y +CONFIG_DEFAULT_SECURITY_APPARMOR=y +CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CRYPTO_USER=m +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_ECRDSA=m +CONFIG_CRYPTO_CURVE25519=m +CONFIG_CRYPTO_AES_TI=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_ADIANTUM=m +CONFIG_CRYPTO_CFB=m +CONFIG_CRYPTO_KEYWRAP=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_OFB=m +CONFIG_CRYPTO_AEGIS128=m +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_SM3_GENERIC=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_LZ4=m +CONFIG_CRYPTO_LZ4HC=m +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set +CONFIG_CRYPTO_DEV_CHELSIO=m +CONFIG_CRYPTO_DEV_VIRTIO=m +CONFIG_PKCS8_PRIVATE_KEY_PARSER=m +CONFIG_SECONDARY_TRUSTED_KEYRING=y +CONFIG_SYSTEM_BLACKLIST_KEYRING=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_TER16x32=y +CONFIG_PRINTK_TIME=y +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_DEBUG_INFO_BTF=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6 +CONFIG_PAGE_EXTENSION=y +CONFIG_PAGE_POISONING=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_KFENCE=y +CONFIG_KFENCE_SAMPLE_INTERVAL=0 +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_SCHEDSTATS=y +CONFIG_DEBUG_LIST=y +# CONFIG_RCU_TRACE is not set +CONFIG_FPROBE=y +CONFIG_STACK_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_IO_STRICT_DEVMEM=y +CONFIG_NOTIFIER_ERROR_INJECTION=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_STATIC_KEYS=m From 9708a66ba7634b78d221110cbd7ae55957591405 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Wed, 27 Sep 2023 02:54:09 +0800 Subject: [PATCH 19/52] [NFU] config: mmc_block & ext4 builtin Signed-off-by: Han Gao --- arch/riscv/configs/revyos_defconfig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/riscv/configs/revyos_defconfig b/arch/riscv/configs/revyos_defconfig index ee8c63d2383775..954db09f24f420 100644 --- a/arch/riscv/configs/revyos_defconfig +++ b/arch/riscv/configs/revyos_defconfig @@ -80,6 +80,7 @@ CONFIG_BLK_SED_OPAL=y CONFIG_PARTITION_ADVANCED=y CONFIG_KARMA_PARTITION=y CONFIG_MQ_IOSCHED_KYBER=m +CONFIG_IOSCHED_BFQ=m CONFIG_BINFMT_MISC=m CONFIG_ZSWAP=y CONFIG_Z3FOLD=m @@ -1618,7 +1619,6 @@ CONFIG_FB_MB862XX=m CONFIG_FIRMWARE_EDID=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_PWM=m -CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_SOUND=m # CONFIG_SOUND_OSS_CORE_PRECLAIM is not set @@ -1933,7 +1933,6 @@ CONFIG_NOP_USB_XCEIV=m CONFIG_MMC=y CONFIG_PWRSEQ_EMMC=m CONFIG_PWRSEQ_SIMPLE=m -CONFIG_MMC_BLOCK=m CONFIG_MMC_BLOCK_MINORS=256 CONFIG_SDIO_UART=m CONFIG_MMC_SDHCI=y @@ -2261,7 +2260,7 @@ CONFIG_PWM_SIFIVE=m CONFIG_RESET_SIMPLE=y CONFIG_LIBNVDIMM=m CONFIG_DEV_DAX=m -CONFIG_EXT4_FS=m +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_REISERFS_FS=m @@ -2479,13 +2478,17 @@ CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_ADIANTUM=m CONFIG_CRYPTO_CFB=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_KEYWRAP=m CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_OFB=m +CONFIG_CRYPTO_XTS=m CONFIG_CRYPTO_AEGIS128=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_SM3_GENERIC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_WP512=m From 04a4c71a7d7d3544aaa88692f3d21dc39561a831 Mon Sep 17 00:00:00 2001 From: Robert Nelson Date: Wed, 27 Sep 2023 17:25:30 -0500 Subject: [PATCH 20/52] th1520-beaglev-ahead.dts Signed-off-by: Robert Nelson --- .../boot/dts/thead/th1520-beaglev-ahead.dts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts index f91d94f955102b..89163615d2e6e3 100644 --- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts +++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts @@ -13,6 +13,7 @@ compatible = "beagle,beaglev-ahead", "thead,th1520"; aliases { + ethernet0 = &gmac0; gpio0 = &gpio0; gpio1 = &gpio1; gpio2 = &gpio2; @@ -60,6 +61,26 @@ status = "okay"; }; +&gmac_clk { + clock-frequency = <500000000>; +}; + +&gmac_axi_clk { + clock-frequency = <100000000>; +}; + +&mdio0 { + phy0: ethernet-phy@1 { + reg = <1>; + }; +}; + +&gmac0 { + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + &mmc0 { bus-width = <8>; max-frequency = <198000000>; From 046a294a3f18a9225407f3523b5d365d79de8cc8 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 28 Sep 2023 00:42:21 +0800 Subject: [PATCH 21/52] dt-bindings: usb: Add T-HEAD TH1520 USB controller T-HEAD TH1520 platform's USB has a wrapper module around the DesignWare USB3 DRD controller. Add binding information doc for it. Signed-off-by: Jisheng Zhang --- .../bindings/usb/thead,th1520-usb.yaml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml diff --git a/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml new file mode 100644 index 00000000000000..afb618eb501390 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/thead,th1520-usb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD TH1520 DWC3 USB Controller Glue + +maintainers: + - Jisheng Zhang + +properties: + compatible: + const: thead,th1520-usb + + reg: + maxItems: 1 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: ref + - const: bus_early + - const: phy + - const: suspend + + ranges: true + + '#address-cells': + enum: [ 1, 2 ] + + '#size-cells': + enum: [ 1, 2 ] + +# Required child node: + +patternProperties: + "^usb@[0-9a-f]+$": + $ref: snps,dwc3.yaml# + +required: + - compatible + - reg + - clocks + - clock-names + - ranges + +additionalProperties: false + +examples: + - | + + usb { + compatible = "thead,th1520-usb"; + reg = <0xec03f000 0x1000>; + clocks = <&clk 1>, + <&clk 2>, + <&clk 3>, + <&clk 4>; + clock-names = "ref", "bus_early", "phy", "suspend"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + + usb@e7040000 { + compatible = "snps,dwc3"; + reg = <0xe7040000 0x10000>; + interrupts = <68>; + dr_mode = "host"; + }; + }; From 910495c80e2c383c86be33a744dbcc03196fe560 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 28 Sep 2023 00:42:22 +0800 Subject: [PATCH 22/52] usb: dwc3: add T-HEAD TH1520 usb driver Adds TH1520 Glue layer to support USB controller on T-HEAD TH1520 SoC. There is a DesignWare USB3 DRD core in TH1520 SoCs, the dwc3 core is the child of this USB wrapper module device. Signed-off-by: Jisheng Zhang --- MAINTAINERS | 1 + drivers/usb/dwc3/Kconfig | 9 +++ drivers/usb/dwc3/Makefile | 1 + drivers/usb/dwc3/dwc3-thead.c | 119 ++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 drivers/usb/dwc3/dwc3-thead.c diff --git a/MAINTAINERS b/MAINTAINERS index dd5de540ec0b52..bf3539259685d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18481,6 +18481,7 @@ M: Fu Wei L: linux-riscv@lists.infradead.org S: Maintained F: arch/riscv/boot/dts/thead/ +F: drivers/usb/dwc3/dwc3-thead.c RNBD BLOCK DRIVERS M: Md. Haris Iqbal diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 98efcbb76c8821..1b02f4f55b47b4 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -178,4 +178,13 @@ config USB_DWC3_OCTEON Only the host mode is currently supported. Say 'Y' or 'M' here if you have one such device. +config USB_DWC3_THEAD + tristate "T-HEAD Platform" + depends on ARCH_THEAD || COMPILE_TEST + default USB_DWC3 + help + Support T-HEAD platform with DesignWare Core USB3 IP. + Only the host mode is currently supported. + Say 'Y' or 'M' here if you have one such device. + endif diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index fe1493d4bbe58e..9523a51dd27979 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -55,3 +55,4 @@ obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o +obj-$(CONFIG_USB_DWC3_THEAD) += dwc3-thead.o diff --git a/drivers/usb/dwc3/dwc3-thead.c b/drivers/usb/dwc3/dwc3-thead.c new file mode 100644 index 00000000000000..324944ed48f692 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-thead.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dwc3-thead.c - T-HEAD platform specific glue layer + * + * Inspired by dwc3-of-simple.c + * + * Copyright (C) 2021 Alibaba Group Holding Limited. + * Copyright (C) 2023 Jisheng Zhang + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" + +#define USB_SSP_EN 0x34 +#define REF_SSP_EN BIT(0) +#define USB_SYS 0x3c +#define COMMONONN BIT(0) + +#define USB3_DRD_SWRST 0x14 +#define USB3_DRD_PRST BIT(0) +#define USB3_DRD_PHYRST BIT(1) +#define USB3_DRD_VCCRST BIT(2) +#define USB3_DRD_RSTMASK (USB3_DRD_PRST | USB3_DRD_PHYRST | USB3_DRD_VCCRST) + +struct dwc3_thead { + void __iomem *base; + struct regmap *misc_sysreg; + struct regulator *vbus; +}; + +static void dwc3_thead_optimize_power(struct dwc3_thead *thead) +{ + u32 val; + + /* config usb top within USB ctrl & PHY reset */ + regmap_update_bits(thead->misc_sysreg, USB3_DRD_SWRST, + USB3_DRD_RSTMASK, USB3_DRD_PRST); + + /* + * dwc reg also need to be configed to save power + * 1. set USB_SYS[COMMONONN] + * 2. set DWC3_GCTL[SOFITPSYNC](done by core.c) + * 3. set GUSB3PIPECTL[SUSPENDEN] (done by core.c) + */ + val = readl(thead->base + USB_SYS); + val |= COMMONONN; + writel(val, thead->base + USB_SYS); + val = readl(thead->base + USB_SSP_EN); + val |= REF_SSP_EN; + writel(val, thead->base + USB_SSP_EN); + + regmap_update_bits(thead->misc_sysreg, USB3_DRD_SWRST, + USB3_DRD_RSTMASK, USB3_DRD_RSTMASK); +} + +static int dwc3_thead_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct dwc3_thead *thead; + int ret; + + thead = devm_kzalloc(&pdev->dev, sizeof(*thead), GFP_KERNEL); + if (!thead) + return -ENOMEM; + + platform_set_drvdata(pdev, thead); + + ret = devm_regulator_get_enable_optional(dev, "vbus"); + if (ret < 0 && ret != -ENODEV) + return ret; + + thead->misc_sysreg = syscon_regmap_lookup_by_phandle(np, "thead,misc-sysreg"); + if (IS_ERR(thead->misc_sysreg)) + return PTR_ERR(thead->misc_sysreg); + + thead->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(thead->base)) + return PTR_ERR(thead->base); + + dwc3_thead_optimize_power(thead); + + return of_platform_populate(np, NULL, NULL, dev); +} + +static void dwc3_thead_remove(struct platform_device *pdev) +{ + of_platform_depopulate(&pdev->dev); +} + +static const struct of_device_id dwc3_thead_of_match[] = { + { .compatible = "thead,th1520-usb" }, + { }, +}; +MODULE_DEVICE_TABLE(of, dwc3_thead_of_match); + +static struct platform_driver dwc3_thead_driver = { + .probe = dwc3_thead_probe, + .remove_new = dwc3_thead_remove, + .driver = { + .name = "dwc3-thead", + .of_match_table = dwc3_thead_of_match, + }, +}; +module_platform_driver(dwc3_thead_driver); + +MODULE_ALIAS("platform:dwc3-thead"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DesignWare DWC3 T-HEAD Glue Driver"); +MODULE_AUTHOR("Jisheng Zhang "); From 48b483ebc1913f500eb7e9b06903a55dec10042d Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 5 Oct 2023 21:05:18 +0800 Subject: [PATCH 23/52] dt-bindings: pwm: Add T-HEAD PWM controller T-HEAD SoCs such as the TH1520 contain a PWM controller used to control the LCD backlight, fan and so on. Signed-off-by: Jisheng Zhang Reviewed-by: Rob Herring --- .../bindings/pwm/thead,th1520-pwm.yaml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml diff --git a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml new file mode 100644 index 00000000000000..e75d8e9f24c50b --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/thead,th1520-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD TH1520 PWM + +maintainers: + - Jisheng Zhang + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + enum: + - thead,th1520-pwm + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + "#pwm-cells": + const: 3 + +required: + - compatible + - reg + - clocks + +additionalProperties: false + +examples: + - | + + pwm@ec01c000 { + compatible = "thead,th1520-pwm"; + reg = <0xec01c000 0x1000>; + clocks = <&clk 1>; + #pwm-cells = <3>; + }; From 22a6757dec8366a5cfe92b318ece5f124f774575 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 5 Oct 2023 21:05:19 +0800 Subject: [PATCH 24/52] pwm: add T-HEAD PWM driver T-HEAD SoCs such as the TH1520 contain a PWM controller used to control the LCD backlight, fan and so on. Add driver for it. Signed-off-by: Jisheng Zhang --- drivers/pwm/Kconfig | 11 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-thead.c | 270 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 drivers/pwm/pwm-thead.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 8ebcddf91f7b78..428fa365a19a47 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -637,6 +637,17 @@ config PWM_TEGRA To compile this driver as a module, choose M here: the module will be called pwm-tegra. +config PWM_THEAD + tristate "T-HEAD PWM support" + depends on ARCH_THEAD || COMPILE_TEST + depends on HAS_IOMEM + help + Generic PWM framework driver for the PWFM controller found on THEAD + SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-thead. + config PWM_TIECAP tristate "ECAP PWM support" depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c822389c2a24c2..4c317e6316e83d 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o obj-$(CONFIG_PWM_SUNPLUS) += pwm-sunplus.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o +obj-$(CONFIG_PWM_THEAD) += pwm-thead.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o obj-$(CONFIG_PWM_TWL) += pwm-twl.o diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c new file mode 100644 index 00000000000000..3b9ffddfe33dbd --- /dev/null +++ b/drivers/pwm/pwm-thead.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * T-HEAD PWM driver + * + * Copyright (C) 2021 Alibaba Group Holding Limited. + * Copyright (C) 2023 Jisheng Zhang + * + * Limitations: + * - The THEAD_PWM_CTRL_START bit is only effective when 0 -> 1, which is used + * to start the channel, 1 -> 0 doesn't change anything. so 0 % duty cycle + * is used to "disable" the channel. + * - The THEAD_PWM_CTRL_START bit is automatically cleared once PWM channel is + * started. + * - The THEAD_PWM_CFG_UPDATE atomically updates and only updates period and duty. + * - To update period and duty, THEAD_PWM_CFG_UPDATE needs to go through 0 -> 1 + * step, I.E if THEAD_PWM_CFG_UPDATE is already 1, it's necessary to clear it + * to 0 beforehand. + * - Polarity can only be changed if never started before. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define THEAD_PWM_MAX_NUM 6 +#define THEAD_PWM_MAX_PERIOD GENMASK(31, 0) +#define THEAD_PWM_MAX_DUTY GENMASK(31, 0) + +#define THEAD_PWM_CHN_BASE(n) ((n) * 0x20) +#define THEAD_PWM_CTRL(n) (THEAD_PWM_CHN_BASE(n) + 0x00) +#define THEAD_PWM_CTRL_START BIT(0) +#define THEAD_PWM_CTRL_SOFT_RST BIT(1) +#define THEAD_PWM_CTRL_CFG_UPDATE BIT(2) +#define THEAD_PWM_CTRL_INTEN BIT(3) +#define THEAD_PWM_CTRL_MODE GENMASK(5, 4) +#define THEAD_PWM_CTRL_MODE_CONTINUOUS FIELD_PREP(THEAD_PWM_CTRL_MODE, 2) +#define THEAD_PWM_CTRL_EVTRIG GENMASK(7, 6) +#define THEAD_PWM_CTRL_FPOUT BIT(8) +#define THEAD_PWM_CTRL_INFACTOUT BIT(9) +#define THEAD_PWM_RPT(n) (THEAD_PWM_CHN_BASE(n) + 0x04) +#define THEAD_PWM_PER(n) (THEAD_PWM_CHN_BASE(n) + 0x08) +#define THEAD_PWM_FP(n) (THEAD_PWM_CHN_BASE(n) + 0x0c) +#define THEAD_PWM_STATUS(n) (THEAD_PWM_CHN_BASE(n) + 0x10) +#define THEAD_PWM_STATUS_CYCLE GENMASK(7, 0) + +struct thead_pwm_chip { + struct pwm_chip chip; + void __iomem *mmio_base; + struct clk *clk; + u8 channel_ever_started; +}; + +static inline struct thead_pwm_chip *thead_pwm_from_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct thead_pwm_chip, chip); +} + +static int thead_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); + u32 val = THEAD_PWM_CTRL_INFACTOUT | THEAD_PWM_CTRL_FPOUT | THEAD_PWM_CTRL_MODE_CONTINUOUS; + u64 period_cycle, duty_cycle, rate; + int ret; + + /* if ever started, can't change the polarity */ + if ((priv->channel_ever_started & (1 << pwm->hwpwm)) && + state->polarity != pwm->state.polarity) + return -EINVAL; + + if (!state->enabled) { + if (pwm->state.enabled) { + val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); + val &= ~THEAD_PWM_CTRL_CFG_UPDATE; + writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); + + writel(0, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); + + val |= THEAD_PWM_CTRL_CFG_UPDATE; + writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); + pm_runtime_put_sync(chip->dev); + } + return 0; + } + + if (!pwm->state.enabled) { + ret = pm_runtime_resume_and_get(chip->dev); + if (ret < 0) + return ret; + } + + if (state->polarity == PWM_POLARITY_INVERSED) + val &= ~THEAD_PWM_CTRL_FPOUT; + + writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); + + rate = clk_get_rate(priv->clk); + /* + * The following calculations might overflow if clk is bigger + * than 1 GHz. In practise it's 24MHz, so this limitation + * is only theoretic. + */ + if (rate > NSEC_PER_SEC) + return -EINVAL; + + period_cycle = mul_u64_u64_div_u64(rate, state->period, NSEC_PER_SEC); + if (period_cycle > THEAD_PWM_MAX_PERIOD) + period_cycle = THEAD_PWM_MAX_PERIOD; + /* + * With limitation above we have period_cycle <= THEAD_PWM_MAX_PERIOD, + * so this cannot overflow. + */ + writel(period_cycle, priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); + + duty_cycle = mul_u64_u64_div_u64(rate, state->duty_cycle, NSEC_PER_SEC); + if (duty_cycle > THEAD_PWM_MAX_DUTY) + duty_cycle = THEAD_PWM_MAX_DUTY; + /* + * With limitation above we have duty_cycle <= THEAD_PWM_MAX_DUTY, + * so this cannot overflow. + */ + writel(duty_cycle, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); + + val |= THEAD_PWM_CTRL_CFG_UPDATE; + writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); + + if (!pwm->state.enabled) { + val |= THEAD_PWM_CTRL_START; + writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); + priv->channel_ever_started |= 1 << pwm->hwpwm; + } + + return 0; +} + +static int thead_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); + u64 rate = clk_get_rate(priv->clk); + u32 val; + int ret; + + ret = pm_runtime_resume_and_get(chip->dev); + if (ret < 0) + return ret; + + val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); + if (val & THEAD_PWM_CTRL_FPOUT) + state->polarity = PWM_POLARITY_NORMAL; + else + state->polarity = PWM_POLARITY_INVERSED; + + val = readl(priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); + /* + * val 32 bits, multiply NSEC_PER_SEC, won't overflow. + */ + state->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); + + val = readl(priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); + state->enabled = !!val; + /* + * val 32 bits, multiply NSEC_PER_SEC, won't overflow. + */ + state->duty_cycle = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); + + pm_runtime_put_sync(chip->dev); + + return 0; +} + +static const struct pwm_ops thead_pwm_ops = { + .apply = thead_pwm_apply, + .get_state = thead_pwm_get_state, + .owner = THIS_MODULE, +}; + +static int __maybe_unused thead_pwm_runtime_suspend(struct device *dev) +{ + struct thead_pwm_chip *priv = dev_get_drvdata(dev); + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int __maybe_unused thead_pwm_runtime_resume(struct device *dev) +{ + struct thead_pwm_chip *priv = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + dev_err(dev, "failed to enable pwm clock(%pe)\n", ERR_PTR(ret)); + + return ret; +} + +static int thead_pwm_probe(struct platform_device *pdev) +{ + struct thead_pwm_chip *priv; + int ret, i; + u32 val; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + priv->mmio_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->mmio_base)) + return PTR_ERR(priv->mmio_base); + + priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + priv->chip.ops = &thead_pwm_ops; + priv->chip.dev = &pdev->dev; + priv->chip.npwm = THEAD_PWM_MAX_NUM; + + /* check whether PWM is ever started or not */ + for (i = 0; i < priv->chip.npwm; i++) { + val = readl(priv->mmio_base + THEAD_PWM_FP(i)); + if (val) + priv->channel_ever_started |= 1 << i; + } + + ret = devm_pwmchip_add(&pdev->dev, &priv->chip); + if (ret) + return ret; + + devm_pm_runtime_enable(&pdev->dev); + + return 0; +} + +static const struct of_device_id thead_pwm_dt_ids[] = { + {.compatible = "thead,th1520-pwm",}, + {/* sentinel */} +}; +MODULE_DEVICE_TABLE(of, thead_pwm_dt_ids); + +static const struct dev_pm_ops thead_pwm_pm_ops = { + SET_RUNTIME_PM_OPS(thead_pwm_runtime_suspend, thead_pwm_runtime_resume, NULL) +}; + +static struct platform_driver thead_pwm_driver = { + .driver = { + .name = "thead-pwm", + .of_match_table = thead_pwm_dt_ids, + .pm = &thead_pwm_pm_ops, + }, + .probe = thead_pwm_probe, +}; +module_platform_driver(thead_pwm_driver); + +MODULE_AUTHOR("Wei Liu "); +MODULE_AUTHOR("Jisheng Zhang "); +MODULE_DESCRIPTION("T-HEAD pwm driver"); +MODULE_LICENSE("GPL v2"); From 80d58ce28816e2aa3de920832cc079cbdd997a9a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 13:50:07 +0800 Subject: [PATCH 25/52] riscv: dts: thead: add i2c dt nodes Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/thead/th1520.dtsi | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index b9239339e34c74..f837bc7278152a 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -371,6 +371,76 @@ status = "disabled"; }; + i2c0: i2c@ffe7f20000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xe7f20000 0x0 0x1000>; + clocks = <&apb_clk>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@ffe7f24000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xe7f24000 0x0 0x1000>; + clocks = <&apb_clk>; + interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@ffe7f28000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xe7f28000 0x0 0x1000>; + clocks = <&apb_clk>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@ffec00c000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xec00c000 0x0 0x1000>; + clocks = <&apb_clk>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@ffec014000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xec014000 0x0 0x1000>; + clocks = <&apb_clk>; + interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + audio_i2c0: i2c@ffcb01a000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xcb01a000 0x0 0x1000>; + clocks = <&apb_clk>; + interrupts = <182 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + audio_i2c1: i2c@ffcb01b000 { + compatible = "snps,designware-i2c"; + reg = <0xff 0xcb01b000 0x0 0x1000>; + clocks = <&apb_clk>; + interrupts = <183 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + dmac0: dma-controller@ffefc00000 { compatible = "snps,axi-dma-1.01a"; reg = <0xff 0xefc00000 0x0 0x1000>; From 7591246bd233a2a88d73b6ef174450db1270b5c5 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 13:51:56 +0800 Subject: [PATCH 26/52] riscv: dts: thead: add usb dt node Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/thead/th1520.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index f837bc7278152a..25be4a2fd48ba6 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -421,6 +421,29 @@ status = "disabled"; }; + misc_sysreg: misc_sysreg@ffec02c000 { + compatible = "thead,th1520-misc-sysreg", "syscon"; + reg = <0xff 0xec02c000 0x0 0x1000>; + }; + + usb: usb@ffec03f000 { + compatible = "thead,th1520-usb"; + reg = <0xff 0xec03f000 0x0 0x1000>; + thead,misc-sysreg = <&misc_sysreg>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + usb_dwc3: dwc3@ffe7040000 { + compatible = "snps,dwc3"; + reg = <0xff 0xe7040000 0x0 0x10000>; + interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; + dr_mode = "host"; + snps,usb3_lpm_capable; + status = "disabled"; + }; + }; + audio_i2c0: i2c@ffcb01a000 { compatible = "snps,designware-i2c"; reg = <0xff 0xcb01a000 0x0 0x1000>; From 1127478f436d8bacf4b668c314e6186552a9bb56 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 13:56:37 +0800 Subject: [PATCH 27/52] riscv: dts: lpi4a: enable usb Signed-off-by: Jisheng Zhang --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index ccdcb580b27410..556bc17f5aa0bd 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -3,6 +3,8 @@ * Copyright (C) 2023 Jisheng Zhang */ +#include + #include "th1520-lichee-module-4a.dtsi" / { @@ -22,11 +24,38 @@ serial3 = &uart3; serial4 = &uart4; serial5 = &uart5; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &audio_i2c0; + i2c6 = &audio_i2c1; }; chosen { stdout-path = "serial0:115200n8"; }; + + hub_5v: regulator-hub_5v { + compatible = "regulator-fixed"; + regulator-name = "HUB_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&pca9557_2 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; + + vcc5v_usb: regulator-vcc5v_usb { + compatible = "regulator-fixed"; + regulator-name = "VCC5V_USB"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&portb 22 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; }; &mdio0 { @@ -55,3 +84,52 @@ &uart0 { status = "okay"; }; + +&i2c3 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + pca9557_2: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + +&porte { + sel-usb-hub-hog { + gpio-hog; + gpios = <4 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&usb { + status = "okay"; +}; + +&usb_dwc3 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + hub_2_0: hub@1 { + compatible = "usb2109,2817"; + reg = <1>; + peer-hub = <&hub_3_0>; + vdd-supply = <&hub_5v>; + vbus-supply = <&vcc5v_usb>; + }; + + hub_3_0: hub@2 { + compatible = "usb2109,817"; + reg = <2>; + peer-hub = <&hub_2_0>; + vbus-supply = <&vcc5v_usb>; + }; +}; + From b8c94a85d3afb7a9bdbd8e2872b10a836632e660 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 14:00:40 +0800 Subject: [PATCH 28/52] riscv: dts: th1520: add pwm node Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/thead/th1520.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 25be4a2fd48ba6..a33dddb08d2c1a 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -421,6 +421,13 @@ status = "disabled"; }; + pwm: pwm@ffec01c000 { + compatible = "thead,th1520-pwm"; + reg = <0xff 0xec01c000 0x0 0x4000>; + #pwm-cells = <3>; + clocks = <&osc>; + }; + misc_sysreg: misc_sysreg@ffec02c000 { compatible = "thead,th1520-misc-sysreg", "syscon"; reg = <0xff 0xec02c000 0x0 0x1000>; From 57013421a0f3f0e72d7937fa5f8bb77ec599c8fe Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 14:01:12 +0800 Subject: [PATCH 29/52] riscv: dts: lpi4a: enable pwm Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 556bc17f5aa0bd..fa25ea25109a1a 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -133,3 +133,6 @@ }; }; +&pwm { + status = "okay"; +}; From e2ad149fa9cd300553c1c2664f9b1b908b971598 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 16:00:03 +0800 Subject: [PATCH 30/52] riscv: dts: th1520: add pvt dt node Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/thead/th1520.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index a33dddb08d2c1a..e714d271f56c6d 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -128,6 +128,12 @@ #clock-cells = <0>; }; + aonsys_clk: aonsys-clk { + compatible = "fixed-clock"; + clock-output-names = "aonsys_clk"; + #clock-cells = <0>; + }; + uart_sclk: uart-sclk-clock { compatible = "fixed-clock"; clock-output-names = "uart_sclk"; @@ -615,6 +621,18 @@ }; }; + pvt: pvt@fffff4e000 { + compatible = "moortec,mr75203"; + reg = <0xff 0xfff4e000 0x0 0x80>, + <0xff 0xfff4e080 0x0 0x100>, + <0xff 0xfff4e180 0x0 0x680>, + <0xff 0xfff4e800 0x0 0x600>; + reg-names = "common", "ts", "pd", "vm"; + clocks = <&aonsys_clk>; + #thermal-sensor-cells = <1>; + status = "disabled"; + }; + ao_gpio1: gpio@fffff52000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xfff52000 0x0 0x1000>; From bdb0ad928bd8c0c5620d2d4f1bb9e623bb856f7b Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 16:04:47 +0800 Subject: [PATCH 31/52] riscv: dts: lpi4a: enable pvt Signed-off-by: Jisheng Zhang --- arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi | 4 ++++ arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index ba38b3e76b81ff..6b9202df89cc22 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -45,6 +45,10 @@ clock-frequency = <100000000>; }; +&aonsys_clk { + clock-frequency = <73728000>; +}; + &dmac0 { status = "okay"; }; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index fa25ea25109a1a..eadf82146cc637 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -133,6 +133,10 @@ }; }; +&pvt { + status = "okay"; +}; + &pwm { status = "okay"; }; From a7421da8e1c30cb6bb7aef0bbdfe3cc292c4b0b3 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 21 Sep 2023 16:08:30 +0800 Subject: [PATCH 32/52] riscv: dts: thead: lpi4a: enable pwm fan Signed-off-by: Jisheng Zhang --- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index eadf82146cc637..98a2cca1da6a38 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -37,6 +37,58 @@ stdout-path = "serial0:115200n8"; }; + fan: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + pwms = <&pwm 1 10000000 0>; + cooling-levels = <0 66 196 255>; + }; + + thermal-zones { + cpu-thermal { + polling-delay = <1000>; + polling-delay-passive = <1000>; + thermal-sensors = <&pvt 0>; + + trips { + trip_active0: active-0 { + temperature = <39000>; + hysteresis = <5000>; + type = "active"; + }; + + trip_active1: active-1 { + temperature = <50000>; + hysteresis = <5000>; + type = "active"; + }; + + trip_active2: active-2 { + temperature = <60000>; + hysteresis = <5000>; + type = "active"; + }; + }; + + cooling-maps { + map-active-0 { + cooling-device = <&fan 1 1>; + trip = <&trip_active0>; + }; + + map-active-1 { + cooling-device = <&fan 2 2>; + trip = <&trip_active1>; + }; + + map-active-2 { + cooling-device = <&fan 3 3>; + trip = <&trip_active2>; + }; + }; + }; + }; + hub_5v: regulator-hub_5v { compatible = "regulator-fixed"; regulator-name = "HUB_5V"; From 411b5ab3d8914ac5eb1ecabe1e16ee5786013f77 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Sun, 1 Oct 2023 14:54:48 +0800 Subject: [PATCH 33/52] [NFU] config: enable pvt & usb Signed-off-by: Han Gao --- arch/riscv/configs/revyos_defconfig | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/arch/riscv/configs/revyos_defconfig b/arch/riscv/configs/revyos_defconfig index 954db09f24f420..ecbffdd34e44f2 100644 --- a/arch/riscv/configs/revyos_defconfig +++ b/arch/riscv/configs/revyos_defconfig @@ -929,7 +929,7 @@ CONFIG_SMSC9420=m CONFIG_STMMAC_ETH=y CONFIG_DWMAC_DWC_QOS_ETH=m CONFIG_DWMAC_GENERIC=m -CONFIG_DWMAC_THEAD=y +CONFIG_DWMAC_THEAD=m CONFIG_DWMAC_INTEL_PLAT=m CONFIG_CASSINI=m CONFIG_NIU=m @@ -1244,6 +1244,8 @@ CONFIG_I2C_VIPERBOARD=m CONFIG_SPI=y CONFIG_SPI_BUTTERFLY=m CONFIG_SPI_CADENCE_QUADSPI=m +CONFIG_SPI_DESIGNWARE=m +CONFIG_SPI_DW_MMIO=m CONFIG_SPI_LM70_LLP=m CONFIG_SPI_SIFIVE=m CONFIG_SPI_SPIDEV=y @@ -1256,8 +1258,11 @@ CONFIG_PTP_1588_CLOCK_IDTCM=m CONFIG_PTP_1588_CLOCK_OCP=m CONFIG_PINCTRL=y CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_DWAPB=y CONFIG_GPIO_EXAR=m CONFIG_GPIO_SIFIVE=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_PCI_IDIO_16=m CONFIG_GPIO_PCIE_IDIO_24=m CONFIG_GPIO_VIPERBOARD=m @@ -1317,6 +1322,7 @@ CONFIG_SENSORS_MAX16065=m CONFIG_SENSORS_MAX1668=m CONFIG_SENSORS_MAX6639=m CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MR75203=m CONFIG_SENSORS_ADCXX=m CONFIG_SENSORS_LM70=m CONFIG_SENSORS_LM73=m @@ -1331,6 +1337,7 @@ CONFIG_SENSORS_NCT6775=m CONFIG_SENSORS_NCT7802=m CONFIG_SENSORS_NCT7904=m CONFIG_SENSORS_NPCM7XX=m +CONFIG_SENSORS_PWM_FAN=m CONFIG_SENSORS_SHT21=m CONFIG_SENSORS_SHT3x=m CONFIG_SENSORS_SHT4x=m @@ -1361,7 +1368,10 @@ CONFIG_THERMAL_GOV_FAIR_SHARE=y CONFIG_THERMAL_GOV_BANG_BANG=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_CPU_THERMAL=y +# CONFIG_CPU_FREQ_THERMAL is not set CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_EMULATION=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_SYSFS=y CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT=y @@ -1824,7 +1834,6 @@ CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_LEDS_TRIGGER_USBPORT=m CONFIG_USB_MON=m CONFIG_USB_XHCI_HCD=m -CONFIG_USB_XHCI_PLATFORM=m CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_HCD_PLATFORM=m @@ -1855,6 +1864,11 @@ CONFIG_USBIP_VHCI_HC_PORTS=15 CONFIG_USBIP_VHCI_NR_HCS=8 CONFIG_USBIP_HOST=m CONFIG_USB_MUSB_HDRC=m +CONFIG_USB_MUSB_HOST=y +CONFIG_USB_DWC3=m +CONFIG_USB_DWC3_HOST=y +# CONFIG_USB_DWC3_HAPS is not set +# CONFIG_USB_DWC3_OF_SIMPLE is not set CONFIG_USB_SERIAL=m CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_SIMPLE=m @@ -1929,7 +1943,11 @@ CONFIG_USB_EHSET_TEST_FIXTURE=m CONFIG_USB_ISIGHTFW=m CONFIG_USB_YUREX=m CONFIG_USB_CHAOSKEY=m +CONFIG_USB_ONBOARD_HUB=m CONFIG_NOP_USB_XCEIV=m +CONFIG_USB_GADGET=m +CONFIG_TYPEC=m +CONFIG_USB_ROLE_SWITCH=m CONFIG_MMC=y CONFIG_PWRSEQ_EMMC=m CONFIG_PWRSEQ_SIMPLE=m @@ -2257,6 +2275,7 @@ CONFIG_TSYS02D=m CONFIG_MAX31856=m CONFIG_PWM=y CONFIG_PWM_SIFIVE=m +CONFIG_PWM_THEAD=m CONFIG_RESET_SIMPLE=y CONFIG_LIBNVDIMM=m CONFIG_DEV_DAX=m From f1e9609e4787e5cd904ed42ab92041678b0cbbc4 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Mon, 2 Oct 2023 11:24:22 +0800 Subject: [PATCH 34/52] [NFU] config: enable SVNAPOT/SVPBMT/ZICBOM/ZICBOZ Signed-off-by: Han Gao --- arch/riscv/configs/revyos_defconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/riscv/configs/revyos_defconfig b/arch/riscv/configs/revyos_defconfig index ecbffdd34e44f2..f827a7159ffb38 100644 --- a/arch/riscv/configs/revyos_defconfig +++ b/arch/riscv/configs/revyos_defconfig @@ -41,12 +41,8 @@ CONFIG_KEXEC=y CONFIG_ARCH_THEAD=y CONFIG_SMP=y CONFIG_NUMA=y -# CONFIG_RISCV_ISA_SVNAPOT is not set -# CONFIG_RISCV_ISA_SVPBMT is not set # CONFIG_RISCV_ISA_V is not set # CONFIG_RISCV_ISA_ZBB is not set -# CONFIG_RISCV_ISA_ZICBOM is not set -# CONFIG_RISCV_ISA_ZICBOZ is not set CONFIG_RISCV_SBI_V01=y # CONFIG_RISCV_BOOT_SPINWAIT is not set CONFIG_PM_DEBUG=y From e7f85bfa435b1a997dce414af5350f0ffc9c513c Mon Sep 17 00:00:00 2001 From: chainsx Date: Thu, 12 Oct 2023 00:17:24 +0800 Subject: [PATCH 35/52] riscv: dts: th1520, lpi4a: add sdhci and rtl8723ds nodes --- .../dts/thead/th1520-lichee-module-4a.dtsi | 24 ++++++++++++++ .../boot/dts/thead/th1520-lichee-pi-4a.dts | 33 +++++++++++++++++++ arch/riscv/boot/dts/thead/th1520.dtsi | 18 ++++++++++ 3 files changed, 75 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index 6b9202df89cc22..f03cf94e0dd72b 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -68,3 +68,27 @@ bus-width = <4>; status = "okay"; }; + +&sdhci0 { + bus-width = <4>; + max-frequency = <198000000>; + thead,phy-pull-up; + wprtn_ignore; + status = "okay"; +}; + +&sdhci1 { + bus-width = <4>; + max-frequency = <100000000>; + thead,phy-pull-up; + no-sd; + no-mmc; + non-removable; + thead,io-fixed-1v8; + post-power-on-delay-ms = <50>; + wprtn_ignore; + cap-sd-highspeed; + keep-power-in-suspend; + wakeup-source; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 98a2cca1da6a38..589ac2503eee92 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -108,6 +108,24 @@ enable-active-high; regulator-always-on; }; + + wcn_wifi: wireless-wlan { + compatible = "wlan-platdata"; + clock-names = "clk_wifi"; + ref-clock-frequency = <24000000>; + keep_wifi_power_on; + pinctrl-names = "default"; + wifi_chip_type = "rtl8723ds"; + WIFI,poweren_gpio = <&pca9557_1 5 0>; + status = "okay"; + }; + + wcn_bt: wireless-bluetooth { + compatible = "bluetooth-platdata"; + pinctrl-names = "default", "rts_gpio"; + BT,power_gpio = <&pca9557_1 6 0>; + status = "okay"; + }; }; &mdio0 { @@ -137,6 +155,21 @@ status = "okay"; }; +&i2c1 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + status = "okay"; + + pca9557_1: gpio@18 { + compatible = "nxp,pca9557"; + reg = <0x18>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + &i2c3 { clock-frequency = <100000>; i2c-sda-hold-time-ns = <300>; diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index e714d271f56c6d..cc017cab55685f 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -510,6 +510,24 @@ clock-names = "core"; status = "disabled"; }; + + sdhci0: sd@ffe7090000 { + compatible = "thead,th1520-dwcmshc"; + reg = <0xff 0xe7090000 0x0 0x10000>; + interrupts = <64 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "sdhci0irq"; + clocks = <&sdhci_clk>; + clock-names = "core"; + }; + + sdhci1: sd@ffe70a0000 { + compatible = "thead,th1520-dwcmshc"; + reg = <0xff 0xe70a0000 0x0 0x10000>; + interrupts = <71 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "sdhci1irq"; + clocks = <&sdhci_clk>; + clock-names = "core"; + }; timer0: timer@ffefc32000 { compatible = "snps,dw-apb-timer"; From f21d7b0bdd6e945ddda7b5c462442a97f4ca61ac Mon Sep 17 00:00:00 2001 From: Han Gao Date: Mon, 16 Oct 2023 12:43:27 +0800 Subject: [PATCH 36/52] [NFU] config: enable RTW88_8723DS Signed-off-by: Han Gao --- arch/riscv/configs/revyos_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/configs/revyos_defconfig b/arch/riscv/configs/revyos_defconfig index f827a7159ffb38..5638a0bff9413c 100644 --- a/arch/riscv/configs/revyos_defconfig +++ b/arch/riscv/configs/revyos_defconfig @@ -1123,6 +1123,7 @@ CONFIG_RTW88_8822CE=m CONFIG_RTW88_8822CS=m CONFIG_RTW88_8822CU=m CONFIG_RTW88_8723DE=m +CONFIG_RTW88_8723DS=m CONFIG_RTW88_8723DU=m CONFIG_RTW88_8821CE=m CONFIG_RTW88_8821CS=m From 2e608f1fbaad01140d2c0336866e6e7d6590fd37 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Sun, 22 Oct 2023 23:41:35 +0800 Subject: [PATCH 37/52] riscv: dts: thead: convert isa detection to new properties Convert the th1520 devicetrees to use the new properties "riscv,isa-base" & "riscv,isa-extensions". For compatibility with other projects, "riscv,isa" remains. Reviewed-by: Jisheng Zhang Acked-by: Guo Ren Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/thead/th1520.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index cc017cab55685f..0f23f367879653 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -20,6 +20,9 @@ compatible = "thead,c910", "riscv"; device_type = "cpu"; riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; reg = <0>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -41,6 +44,9 @@ compatible = "thead,c910", "riscv"; device_type = "cpu"; riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; reg = <1>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -62,6 +68,9 @@ compatible = "thead,c910", "riscv"; device_type = "cpu"; riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; reg = <2>; i-cache-block-size = <64>; i-cache-size = <65536>; @@ -83,6 +92,9 @@ compatible = "thead,c910", "riscv"; device_type = "cpu"; riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; reg = <3>; i-cache-block-size = <64>; i-cache-size = <65536>; From ab4946bb48c00ba904bc91ba7dbc30c51e20d986 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 12 Oct 2023 22:37:45 +0800 Subject: [PATCH 38/52] riscv: errata: thead: use riscv_nonstd_cache_ops for CMO Previously, we use alternative mechanism to dynamically patch the CMO operations for THEAD C906/C910 during boot for performance reason. But as pointed out by Arnd, "there is already a significant cost in accessing the invalidated cache lines afterwards, which is likely going to be much higher than the cost of an indirect branch". And indeed, there's no performance difference with GMAC and EMMC per my test on Sipeed Lichee Pi 4A board. Use riscv_nonstd_cache_ops for THEAD C906/C910 CMO to simplify the alternative code, and to acchieve Arnd's goal -- "I think moving the THEAD ops at the same level as all nonstandard operations makes sense, but I'd still leave CMO as an explicit fast path that avoids the indirect branch. This seems like the right thing to do both for readability and for platforms on which the indirect branch has a noticeable overhead." Signed-off-by: Jisheng Zhang Tested-by: Emil Renner Berthing Reviewed-by: Conor Dooley --- arch/riscv/Kconfig.errata | 1 + arch/riscv/errata/thead/errata.c | 75 +++++++++++++++++++++++++++- arch/riscv/include/asm/errata_list.h | 50 +++---------------- 3 files changed, 80 insertions(+), 46 deletions(-) diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata index e2c731cfed8cc6..dedb8b238e73de 100644 --- a/arch/riscv/Kconfig.errata +++ b/arch/riscv/Kconfig.errata @@ -79,6 +79,7 @@ config ERRATA_THEAD_CMO depends on ERRATA_THEAD && MMU select DMA_DIRECT_REMAP select RISCV_DMA_NONCOHERENT + select RISCV_NONSTANDARD_CACHE_OPS default y help This will apply the cache management errata to handle the diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c index 0554ed4bf087cf..591734e53efeaf 100644 --- a/arch/riscv/errata/thead/errata.c +++ b/arch/riscv/errata/thead/errata.c @@ -12,8 +12,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -33,6 +35,75 @@ static bool errata_probe_pbmt(unsigned int stage, return false; } +/* + * dcache.ipa rs1 (invalidate, physical address) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 01010 rs1 000 00000 0001011 + * dcache.iva rs1 (invalidate, virtual address) + * 0000001 00110 rs1 000 00000 0001011 + * + * dcache.cpa rs1 (clean, physical address) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 01001 rs1 000 00000 0001011 + * dcache.cva rs1 (clean, virtual address) + * 0000001 00101 rs1 000 00000 0001011 + * + * dcache.cipa rs1 (clean then invalidate, physical address) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 01011 rs1 000 00000 0001011 + * dcache.civa rs1 (clean then invalidate, virtual address) + * 0000001 00111 rs1 000 00000 0001011 + * + * sync.s (make sure all cache operations finished) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000000 11001 00000 000 00000 0001011 + */ +#define THEAD_inval_A0 ".long 0x0265000b" +#define THEAD_clean_A0 ".long 0x0255000b" +#define THEAD_flush_A0 ".long 0x0275000b" +#define THEAD_SYNC_S ".long 0x0190000b" + +#define THEAD_CMO_OP(_op, _start, _size, _cachesize) \ +asm volatile("mv a0, %1\n\t" \ + "j 2f\n\t" \ + "3:\n\t" \ + THEAD_##_op##_A0 "\n\t" \ + "add a0, a0, %0\n\t" \ + "2:\n\t" \ + "bltu a0, %2, 3b\n\t" \ + THEAD_SYNC_S \ + : : "r"(_cachesize), \ + "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ + "r"((unsigned long)(_start) + (_size)) \ + : "a0") + +static void thead_errata_cache_inv(phys_addr_t paddr, size_t size) +{ + void *vaddr = phys_to_virt(paddr); + + THEAD_CMO_OP(inval, vaddr, size, riscv_cbom_block_size); +} + +static void thead_errata_cache_wback(phys_addr_t paddr, size_t size) +{ + void *vaddr = phys_to_virt(paddr); + + THEAD_CMO_OP(clean, vaddr, size, riscv_cbom_block_size); +} + +static void thead_errata_cache_wback_inv(phys_addr_t paddr, size_t size) +{ + void *vaddr = phys_to_virt(paddr); + + THEAD_CMO_OP(flush, vaddr, size, riscv_cbom_block_size); +} + +static const struct riscv_nonstd_cache_ops thead_errata_cmo_ops = { + .wback = &thead_errata_cache_wback, + .inv = &thead_errata_cache_inv, + .wback_inv = &thead_errata_cache_wback_inv, +}; + static bool errata_probe_cmo(unsigned int stage, unsigned long arch_id, unsigned long impid) { @@ -48,6 +119,7 @@ static bool errata_probe_cmo(unsigned int stage, if (stage == RISCV_ALTERNATIVES_BOOT) { riscv_cbom_block_size = L1_CACHE_BYTES; riscv_noncoherent_supported(); + riscv_noncoherent_register_cache_ops(&thead_errata_cmo_ops); } return true; @@ -77,8 +149,7 @@ static u32 thead_errata_probe(unsigned int stage, if (errata_probe_pbmt(stage, archid, impid)) cpu_req_errata |= BIT(ERRATA_THEAD_PBMT); - if (errata_probe_cmo(stage, archid, impid)) - cpu_req_errata |= BIT(ERRATA_THEAD_CMO); + errata_probe_cmo(stage, archid, impid); if (errata_probe_pmu(stage, archid, impid)) cpu_req_errata |= BIT(ERRATA_THEAD_PMU); diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h index b55b434f005910..ea33288f8a25b4 100644 --- a/arch/riscv/include/asm/errata_list.h +++ b/arch/riscv/include/asm/errata_list.h @@ -24,9 +24,8 @@ #ifdef CONFIG_ERRATA_THEAD #define ERRATA_THEAD_PBMT 0 -#define ERRATA_THEAD_CMO 1 -#define ERRATA_THEAD_PMU 2 -#define ERRATA_THEAD_NUMBER 3 +#define ERRATA_THEAD_PMU 1 +#define ERRATA_THEAD_NUMBER 2 #endif #ifdef __ASSEMBLY__ @@ -94,54 +93,17 @@ asm volatile(ALTERNATIVE( \ #define ALT_THEAD_PMA(_val) #endif -/* - * dcache.ipa rs1 (invalidate, physical address) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000001 01010 rs1 000 00000 0001011 - * dache.iva rs1 (invalida, virtual address) - * 0000001 00110 rs1 000 00000 0001011 - * - * dcache.cpa rs1 (clean, physical address) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000001 01001 rs1 000 00000 0001011 - * dcache.cva rs1 (clean, virtual address) - * 0000001 00101 rs1 000 00000 0001011 - * - * dcache.cipa rs1 (clean then invalidate, physical address) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000001 01011 rs1 000 00000 0001011 - * dcache.civa rs1 (... virtual address) - * 0000001 00111 rs1 000 00000 0001011 - * - * sync.s (make sure all cache operations finished) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000000 11001 00000 000 00000 0001011 - */ -#define THEAD_inval_A0 ".long 0x0265000b" -#define THEAD_clean_A0 ".long 0x0255000b" -#define THEAD_flush_A0 ".long 0x0275000b" -#define THEAD_SYNC_S ".long 0x0190000b" - #define ALT_CMO_OP(_op, _start, _size, _cachesize) \ -asm volatile(ALTERNATIVE_2( \ - __nops(6), \ +asm volatile(ALTERNATIVE( \ + __nops(5), \ "mv a0, %1\n\t" \ "j 2f\n\t" \ "3:\n\t" \ CBO_##_op(a0) \ "add a0, a0, %0\n\t" \ "2:\n\t" \ - "bltu a0, %2, 3b\n\t" \ - "nop", 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ - "mv a0, %1\n\t" \ - "j 2f\n\t" \ - "3:\n\t" \ - THEAD_##_op##_A0 "\n\t" \ - "add a0, a0, %0\n\t" \ - "2:\n\t" \ - "bltu a0, %2, 3b\n\t" \ - THEAD_SYNC_S, THEAD_VENDOR_ID, \ - ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO) \ + "bltu a0, %2, 3b\n\t", \ + 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM) \ : : "r"(_cachesize), \ "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ "r"((unsigned long)(_start) + (_size)) \ From 95aae79a5928231947757cc2653847bce9cb9a2a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 12 Oct 2023 22:37:46 +0800 Subject: [PATCH 39/52] riscv: errata: thead: use pa based instructions for CMO T-HEAD CPUs such as C906/C910/C920 support phy address based CMO, use them so that we don't need to convert to virt address. Signed-off-by: Jisheng Zhang Reviewed-by: Guo Ren --- arch/riscv/errata/thead/errata.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c index 591734e53efeaf..0728e73a964066 100644 --- a/arch/riscv/errata/thead/errata.c +++ b/arch/riscv/errata/thead/errata.c @@ -58,9 +58,9 @@ static bool errata_probe_pbmt(unsigned int stage, * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | * 0000000 11001 00000 000 00000 0001011 */ -#define THEAD_inval_A0 ".long 0x0265000b" -#define THEAD_clean_A0 ".long 0x0255000b" -#define THEAD_flush_A0 ".long 0x0275000b" +#define THEAD_inval_A0 ".long 0x02a5000b" +#define THEAD_clean_A0 ".long 0x0295000b" +#define THEAD_flush_A0 ".long 0x02b5000b" #define THEAD_SYNC_S ".long 0x0190000b" #define THEAD_CMO_OP(_op, _start, _size, _cachesize) \ @@ -79,23 +79,17 @@ asm volatile("mv a0, %1\n\t" \ static void thead_errata_cache_inv(phys_addr_t paddr, size_t size) { - void *vaddr = phys_to_virt(paddr); - - THEAD_CMO_OP(inval, vaddr, size, riscv_cbom_block_size); + THEAD_CMO_OP(inval, paddr, size, riscv_cbom_block_size); } static void thead_errata_cache_wback(phys_addr_t paddr, size_t size) { - void *vaddr = phys_to_virt(paddr); - - THEAD_CMO_OP(clean, vaddr, size, riscv_cbom_block_size); + THEAD_CMO_OP(clean, paddr, size, riscv_cbom_block_size); } static void thead_errata_cache_wback_inv(phys_addr_t paddr, size_t size) { - void *vaddr = phys_to_virt(paddr); - - THEAD_CMO_OP(flush, vaddr, size, riscv_cbom_block_size); + THEAD_CMO_OP(flush, paddr, size, riscv_cbom_block_size); } static const struct riscv_nonstd_cache_ops thead_errata_cmo_ops = { From d6d5dc849cd4f96f0529bd3013d5a93b37fca1f7 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 21 Nov 2023 22:43:40 +0800 Subject: [PATCH 40/52] riscv: select ARCH_HAS_FAST_MULTIPLIER Currently, riscv linux requires at least IMA, so all platforms have a multiplier. And I assume the 'mul' efficiency is comparable or better than a sequence of five or so register-dependent arithmetic instructions. Select ARCH_HAS_FAST_MULTIPLIER to get slightly nicer codegen. Refer to commit f9b4192923fa ("[PATCH] bitops: hweight() speedup") for more details. In a simple benchmark test calling hweight64() in a loop, it got: about 14% preformance improvement on JH7110, tested on Milkv Mars. about 23% performance improvement on TH1520 and SG2042, tested on Sipeed LPI4A and SG2042 platform. a slight performance drop on CV1800B, tested on milkv duo. Among all riscv platforms in my hands, this is the only one which sees a slight performance drop. It means the 'mul' isn't quick enough. However, the situation exists on x86 too, for example, P4 doesn't have fast integer multiplies as said in the above commit, x86 also selects ARCH_HAS_FAST_MULTIPLIER. So let's select ARCH_HAS_FAST_MULTIPLIER which can benefit almost riscv platforms. Signed-off-by: Jisheng Zhang Reviewed-by: Samuel Holland Tested-by: Samuel Holland --- arch/riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6688cbbed0b42f..ffaa3aaa1008c6 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -23,6 +23,7 @@ config RISCV select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_WX + select ARCH_HAS_FAST_MULTIPLIER select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE From fa39b6bdfe568dc86ce325bd4043278c633b1dc2 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sat, 25 Nov 2023 16:21:43 +0800 Subject: [PATCH 41/52] riscv: select ARCH_USE_CMPXCHG_LOCKREF Select ARCH_USE_CMPXCHG_LOCKREF to enable the cmpxchg-based lockless lockref implementation for riscv. Using Linus' test case[1] on TH1520 platform, I see a 11.2% improvement. On JH7110 platform, I see 12.0% improvement. Link: http://marc.info/?l=linux-fsdevel&m=137782380714721&w=4 [1] Signed-off-by: Jisheng Zhang --- arch/riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index ffaa3aaa1008c6..ef46b6d3114928 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -49,6 +49,7 @@ config RISCV select ARCH_SUPPORTS_HUGETLBFS if MMU select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU select ARCH_SUPPORTS_PER_VMA_LOCK if MMU + select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS select ARCH_USES_CFI_TRAPS if CFI_CLANG From 2c4c1fed6c238ff91e54a362b37bd180ab4098ed Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sat, 25 Nov 2023 16:21:44 +0800 Subject: [PATCH 42/52] riscv: cmpxchg: implement arch_cmpxchg64_{relaxed|acquire|release} After selecting ARCH_USE_CMPXCHG_LOCKREF, one straight futher optimization is implementing the arch_cmpxchg64_relaxed() because the lockref code does not need the cmpxchg to have barrier semantics. At the same time, implement arch_cmpxchg64_acquire and arch_cmpxchg64_release as well. However, on both TH1520 and JH7110 platforms, I didn't see obvious performance improvement with Linus' test case [1]. IMHO, this may be related with the fence and lr.d/sc.d hw implementations. In theory, lr/sc without fence could give performance improvement over lr/sc plus fence, so add the code here to leave performance improvement room on newer HW platforms. Link: http://marc.info/?l=linux-fsdevel&m=137782380714721&w=4 [1] Signed-off-by: Jisheng Zhang --- arch/riscv/include/asm/cmpxchg.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 2f4726d3cfcc25..6318187f426f65 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -360,4 +360,22 @@ arch_cmpxchg_relaxed((ptr), (o), (n)); \ }) +#define arch_cmpxchg64_relaxed(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg_relaxed((ptr), (o), (n)); \ +}) + +#define arch_cmpxchg64_acquire(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg_acquire((ptr), (o), (n)); \ +}) + +#define arch_cmpxchg64_release(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg_release((ptr), (o), (n)); \ +}) + #endif /* _ASM_RISCV_CMPXCHG_H */ From f71fdfdb48dd1058048432b12b475f14f1096533 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 31 Oct 2023 22:35:20 +0800 Subject: [PATCH 43/52] riscv: add PREEMPT_AUTO support riscv has switched to GENERIC_ENTRY, so adding PREEMPT_AUTO is as simple as adding TIF_ARCH_RESCHED_LAZY related definitions and enabling HAVE_PREEMPT_AUTO. Signed-off-by: Jisheng Zhang Signed-off-by: Sebastian Andrzej Siewior --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/thread_info.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index ef46b6d3114928..0e5352dbcb95c6 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -137,6 +137,7 @@ config RISCV select HAVE_PERF_USER_STACK_DUMP select HAVE_POSIX_CPU_TIMERS_TASK_WORK select HAVE_PREEMPT_DYNAMIC_KEY if !XIP_KERNEL + select HAVE_PREEMPT_AUTO select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RETHOOK if !XIP_KERNEL select HAVE_RSEQ diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index d18ce0113ca1f1..e18710fe51f056 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -82,6 +82,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); * - pending work-to-be-done flags are in lowest half-word * - other flags in upper half-word(s) */ +#define TIF_ARCH_RESCHED_LAZY 0 /* Lazy rescheduling */ #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ @@ -96,6 +97,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) #define _TIF_UPROBE (1 << TIF_UPROBE) +#define _TIF_ARCH_RESCHED_LAZY (1 << TIF_ARCH_RESCHED_LAZY) #define _TIF_WORK_MASK \ (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \ From be82c88b7d56259fc13c78bfa530e5e9438bfa23 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 31 Oct 2023 22:35:21 +0800 Subject: [PATCH 44/52] riscv: allow to enable RT Now, it's ready to enable RT on riscv. Signed-off-by: Jisheng Zhang Signed-off-by: Sebastian Andrzej Siewior --- arch/riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 0e5352dbcb95c6..469d8ca8618344 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -49,6 +49,7 @@ config RISCV select ARCH_SUPPORTS_HUGETLBFS if MMU select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU select ARCH_SUPPORTS_PER_VMA_LOCK if MMU + select ARCH_SUPPORTS_RT select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS From 462d0f2e2dd6bcd1005ec3cb50e9e064cfcc95ab Mon Sep 17 00:00:00 2001 From: ixgbe01 Date: Fri, 24 Nov 2023 17:22:25 +0800 Subject: [PATCH 45/52] add TH1520 cpu frequency driver --- .../dts/thead/th1520-lichee-module-4a.dtsi | 79 +- .../boot/dts/thead/th1520-lichee-pi-4a.dts | 292 ++++++ arch/riscv/boot/dts/thead/th1520.dtsi | 147 ++- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/thead/Kconfig | 19 + drivers/clk/thead/Makefile | 8 + drivers/clk/thead/clk-light-fm.c | 646 +++++++++++++ drivers/clk/thead/clk-light-mpw.c | 492 ++++++++++ drivers/clk/thead/clk.c | 739 +++++++++++++++ drivers/clk/thead/clk.h | 117 +++ drivers/clk/thead/gate/Makefile | 3 + drivers/clk/thead/gate/clk-gate.h | 35 + drivers/clk/thead/gate/dspsys-gate.c | 109 +++ drivers/clk/thead/gate/thead-gate.c | 114 +++ drivers/clk/thead/gate/visys-gate.c | 144 +++ drivers/clk/thead/gate/vosys-gate.c | 111 +++ drivers/clk/thead/gate/vpsys-gate.c | 94 ++ drivers/cpufreq/Kconfig | 10 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/light-mpw-cpufreq.c | 490 ++++++++++ drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/thead/Kconfig | 18 + drivers/firmware/thead/Makefile | 3 + drivers/firmware/thead/light_aon.c | 244 +++++ drivers/firmware/thead/light_aon_misc.c | 74 ++ drivers/firmware/thead/light_aon_pd.c | 417 ++++++++ drivers/firmware/thead/light_aon_test.c | 163 ++++ drivers/mailbox/Kconfig | 8 + drivers/mailbox/Makefile | 3 + drivers/mailbox/light-mailbox-client.c | 242 +++++ drivers/mailbox/light-mailbox.c | 507 ++++++++++ drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/light-regulator-aon.c | 888 ++++++++++++++++++ include/dt-bindings/clock/light-dspsys.h | 25 + include/dt-bindings/clock/light-fm-ap-clock.h | 513 ++++++++++ include/dt-bindings/clock/light-mpw-clock.h | 222 +++++ include/dt-bindings/clock/light-visys.h | 54 ++ include/dt-bindings/clock/light-vosys.h | 41 + include/dt-bindings/clock/light-vpsys.h | 24 + include/dt-bindings/firmware/thead/rsrc.h | 17 + include/linux/firmware/thead/ipc.h | 70 ++ 44 files changed, 7191 insertions(+), 6 deletions(-) create mode 100644 drivers/clk/thead/Kconfig create mode 100644 drivers/clk/thead/Makefile create mode 100644 drivers/clk/thead/clk-light-fm.c create mode 100644 drivers/clk/thead/clk-light-mpw.c create mode 100644 drivers/clk/thead/clk.c create mode 100644 drivers/clk/thead/clk.h create mode 100644 drivers/clk/thead/gate/Makefile create mode 100644 drivers/clk/thead/gate/clk-gate.h create mode 100644 drivers/clk/thead/gate/dspsys-gate.c create mode 100644 drivers/clk/thead/gate/thead-gate.c create mode 100644 drivers/clk/thead/gate/visys-gate.c create mode 100644 drivers/clk/thead/gate/vosys-gate.c create mode 100644 drivers/clk/thead/gate/vpsys-gate.c create mode 100644 drivers/cpufreq/light-mpw-cpufreq.c create mode 100644 drivers/firmware/thead/Kconfig create mode 100644 drivers/firmware/thead/Makefile create mode 100644 drivers/firmware/thead/light_aon.c create mode 100644 drivers/firmware/thead/light_aon_misc.c create mode 100644 drivers/firmware/thead/light_aon_pd.c create mode 100644 drivers/firmware/thead/light_aon_test.c create mode 100644 drivers/mailbox/light-mailbox-client.c create mode 100644 drivers/mailbox/light-mailbox.c create mode 100644 drivers/regulator/light-regulator-aon.c create mode 100644 include/dt-bindings/clock/light-dspsys.h create mode 100644 include/dt-bindings/clock/light-fm-ap-clock.h create mode 100644 include/dt-bindings/clock/light-mpw-clock.h create mode 100644 include/dt-bindings/clock/light-visys.h create mode 100644 include/dt-bindings/clock/light-vosys.h create mode 100644 include/dt-bindings/clock/light-vpsys.h create mode 100644 include/dt-bindings/firmware/thead/rsrc.h create mode 100644 include/linux/firmware/thead/ipc.h diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index f03cf94e0dd72b..67f846212cb5aa 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -17,7 +17,7 @@ }; }; -&osc { +&osc_24m { clock-frequency = <24000000>; }; @@ -92,3 +92,80 @@ wakeup-source; status = "okay"; }; + +&cpus { + c910_0: cpu@0 { + operating-points = < + /* kHz uV */ + 300000 650000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 800000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + dvdd-supply = <&dvdd_cpu_reg>; + dvddm-supply = <&dvddm_cpu_reg>; + }; + c910_1: cpu@1 { + operating-points = < + /* kHz uV */ + 300000 650000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 800000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + dvdd-supply = <&dvdd_cpu_reg>; + dvddm-supply = <&dvddm_cpu_reg>; + }; + c910_2: cpu@2 { + + operating-points = < + /* kHz uV */ + 300000 650000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 800000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + dvdd-supply = <&dvdd_cpu_reg>; + dvddm-supply = <&dvddm_cpu_reg>; + }; + c910_3: cpu@3 { + + operating-points = < + /* kHz uV */ + 300000 650000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 800000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + dvdd-supply = <&dvdd_cpu_reg>; + dvddm-supply = <&dvddm_cpu_reg>; + }; +}; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 589ac2503eee92..c6ab6e4a7b193a 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -126,6 +126,298 @@ BT,power_gpio = <&pca9557_1 6 0>; status = "okay"; }; + + aon: aon { + compatible = "thead,light-aon"; + mbox-names = "aon"; + mboxes = <&mbox_910t 1 0>; + status = "okay"; + + pd: light-aon-pd { + compatible = "thead,light-aon-pd"; + #power-domain-cells = <1>; + }; + + soc_aud_3v3_en_reg: soc_aud_3v3_en { + compatible = "regulator-fixed"; + regulator-name = "soc_aud_3v3_en"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + enable-active-high; + regulator-always-on; + }; + + soc_aud_1v8_en_reg: soc_aud_1v8_en { + compatible = "regulator-fixed"; + regulator-name = "soc_aud_1v8_en"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + enable-active-high; + regulator-always-on; + }; + + soc_vdd_3v3_en_reg: soc_vdd_3v3_en { + compatible = "regulator-fixed"; + regulator-name = "soc_vdd_3v3_en"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&porta 30 1>; + enable-active-high; + regulator-always-on; + }; + + soc_vdd33_lcd0_en_reg: soc_lcd0_vdd33_en { + compatible = "regulator-fixed"; + regulator-name = "soc_lcd0_vdd33_en"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&pca9557_1 5 1>; + enable-active-high; + }; + + soc_vdd18_lcd0_en_reg: soc_lcd0_vdd18_en { + compatible = "regulator-fixed"; + regulator-name = "soc_lcd0_vdd18_en"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&pca9557_1 6 1>; + enable-active-high; + }; + + soc_vdd5v_se_en_reg: soc_vdd5v_se_en { + compatible = "regulator-fixed"; + regulator-name = "soc_vdd5v_se_en"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&portc 14 1>; + enable-active-high; + regulator-always-on; + }; + + soc_wcn33_en_reg: soc_wcn33_en { + compatible = "regulator-fixed"; + regulator-name = "soc_wcn33_en"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&portc 29 1>; + enable-active-high; + regulator-always-on; + }; + + soc_vbus_en_reg: soc_vbus_en { + compatible = "regulator-fixed"; + regulator-name = "soc_vbus_en"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&portb 22 1>; + enable-active-high; + regulator-always-on; + }; + + + soc_avdd28_rgb_reg: soc_avdd28_rgb { + compatible = "regulator-fixed"; + regulator-name = "soc_avdd28_rgb"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + gpio = <&pca9557_1 1 1>; + enable-active-high; + }; + + soc_dovdd18_rgb_reg: soc_dovdd18_rgb { + compatible = "regulator-fixed"; + regulator-name = "soc_dovdd18_rgb"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + gpio = <&pca9557_1 2 1>; + enable-active-high; + }; + + soc_dvdd12_rgb_reg: soc_dvdd12_rgb { + compatible = "regulator-fixed"; + regulator-name = "soc_dvdd12_rgb"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + gpio = <&pca9557_1 0 1>; + enable-active-high; + }; + + soc_avdd25_ir_reg: soc_avdd25_ir { + compatible = "regulator-fixed"; + regulator-name = "soc_avdd25_ir"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + gpio = <&pca9557_1 5 1>; + enable-active-high; + }; + + soc_dovdd18_ir_reg: soc_dovdd18_ir { + compatible = "regulator-fixed"; + regulator-name = "soc_dovdd18_ir"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&pca9557_1 3 1>; + enable-active-high; + }; + + soc_dvdd12_ir_reg: soc_dvdd12_ir { + compatible = "regulator-fixed"; + regulator-name = "soc_dvdd12_ir"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + gpio = <&pca9557_1 4 1>; + enable-active-high; + }; + + soc_cam2_avdd25_ir_reg: soc_cam2_avdd25_ir { + compatible = "regulator-fixed"; + regulator-name = "soc_cam2_avdd25_ir"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + gpio = <&pca9557_1 7 1>; + enable-active-high; + }; + + soc_cam2_dovdd18_ir_reg: soc_cam2_dovdd18_ir { + compatible = "regulator-fixed"; + regulator-name = "soc_cam2_dovdd18_ir"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&pca9557_1 6 1>; + enable-active-high; + }; + + soc_cam2_dvdd12_ir_reg: soc_cam2_dvdd12_ir { + compatible = "regulator-fixed"; + regulator-name = "soc_cam2_dvdd12_ir"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + gpio = <&pca9557_1 0 1>; + enable-active-high; + }; + + aon_reg_dialog: light-dialog-reg { + compatible = "thead,light-dialog-pmic-ant"; + status = "okay"; + + dvdd_cpu_reg: appcpu_dvdd { + regulator-name = "appcpu_dvdd"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1570000>; + regulator-boot-on; + regulator-always-on; + }; + + dvddm_cpu_reg: appcpu_dvddm { + regulator-name = "appcpu_dvddm"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1570000>; + regulator-boot-on; + regulator-always-on; + }; + + soc_dvdd18_aon_reg: soc_dvdd18_aon { + regulator-name = "soc_dvdd18_aon"; + regulator-boot-on; + regulator-always-on; + }; + + soc_avdd33_usb3_reg: soc_avdd33_usb3 { + regulator-name = "soc_avdd33_usb3"; + regulator-boot-on; + regulator-always-on; + }; + + soc_dvdd08_aon_reg: soc_dvdd08_aon { + regulator-name = "soc_dvdd08_aon"; + regulator-boot-on; + regulator-always-on; + }; + + soc_dvdd08_ddr_reg: soc_dvdd08_ddr { + regulator-name = "soc_dvdd08_ddr"; + regulator-boot-on; + regulator-always-on; + }; + + soc_vdd_ddr_1v8_reg: soc_vdd_ddr_1v8 { + regulator-name = "soc_vdd_ddr_1v8"; + regulator-boot-on; + regulator-always-on; + }; + + soc_vdd_ddr_1v1_reg: soc_vdd_ddr_1v1 { + regulator-name = "soc_vdd_ddr_1v1"; + regulator-boot-on; + regulator-always-on; + }; + + soc_vdd_ddr_0v6_reg: soc_vdd_ddr_0v6 { + regulator-name = "soc_vdd_ddr_0v6"; + regulator-boot-on; + regulator-always-on; + }; + + soc_dvdd18_ap_reg: soc_dvdd18_ap { + regulator-name = "soc_dvdd18_ap"; + regulator-boot-on; + regulator-always-on; + }; + + soc_avdd08_mipi_hdmi_reg: soc_avdd08_mipi_hdmi { + regulator-name = "soc_avdd08_mipi_hdmi"; + regulator-boot-on; + regulator-always-on; + }; + + soc_avdd18_mipi_hdmi_reg: soc_avdd18_mipi_hdmi { + regulator-name = "soc_avdd18_mipi_hdmi"; + regulator-boot-on; + regulator-always-on; + }; + + soc_vdd33_emmc_reg: soc_vdd33_emmc { + regulator-name = "soc_vdd33_emmc"; + regulator-boot-on; + regulator-always-on; + }; + + soc_vdd18_emmc_reg: soc_vdd18_emmc { + regulator-name = "soc_vdd18_emmc"; + regulator-boot-on; + regulator-always-on; + }; + + soc_dovdd18_scan_reg: soc_dovdd18_scan { + regulator-name = "soc_dovdd18_scan"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3600000>; + }; + + soc_dvdd12_scan_reg: soc_dvdd12_scan { + regulator-name = "soc_dvdd12_scan"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3600000>; + }; + + soc_avdd28_scan_en_reg: soc_avdd28_scan_en { + regulator-name = "soc_avdd28_scan_en"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3600000>; + }; + + }; + + c910_cpufreq { + compatible = "thead,light-mpw-cpufreq"; + status = "okay"; + }; + + test: light-aon-test { + compatible = "thead,light-aon-test"; + }; + }; + }; &mdio0 { diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 0f23f367879653..df020db4c43329 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -5,6 +5,8 @@ */ #include +#include +#include / { compatible = "thead,th1520"; @@ -32,6 +34,30 @@ d-cache-sets = <512>; next-level-cache = <&l2_cache>; mmu-type = "riscv,sv39"; + cpu-freq = "1.848Ghz"; + cpu-cacheline = "64Bytes"; + + operating-points = < + /* kHz uV */ + 300000 600000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 750000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + clock-latency = <61036>; + clocks = <&clk C910_CCLK>, + <&clk C910_CCLK_I0>, + <&clk CPU_PLL1_FOUTPOSTDIV>, + <&clk CPU_PLL0_FOUTPOSTDIV>; + clock-names = "c910_cclk", "c910_cclk_i0", + "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; cpu0_intc: interrupt-controller { compatible = "riscv,cpu-intc"; @@ -56,6 +82,30 @@ d-cache-sets = <512>; next-level-cache = <&l2_cache>; mmu-type = "riscv,sv39"; + cpu-freq = "1.848Ghz"; + cpu-cacheline = "64Bytes"; + + operating-points = < + /* kHz uV */ + 300000 600000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 750000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + clock-latency = <61036>; + clocks = <&clk C910_CCLK>, + <&clk C910_CCLK_I0>, + <&clk CPU_PLL1_FOUTPOSTDIV>, + <&clk CPU_PLL0_FOUTPOSTDIV>; + clock-names = "c910_cclk", "c910_cclk_i0", + "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; cpu1_intc: interrupt-controller { compatible = "riscv,cpu-intc"; @@ -80,6 +130,30 @@ d-cache-sets = <512>; next-level-cache = <&l2_cache>; mmu-type = "riscv,sv39"; + cpu-freq = "1.848Ghz"; + cpu-cacheline = "64Bytes"; + + operating-points = < + /* kHz uV */ + 300000 600000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 750000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + clock-latency = <61036>; + clocks = <&clk C910_CCLK>, + <&clk C910_CCLK_I0>, + <&clk CPU_PLL1_FOUTPOSTDIV>, + <&clk CPU_PLL0_FOUTPOSTDIV>; + clock-names = "c910_cclk", "c910_cclk_i0", + "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; cpu2_intc: interrupt-controller { compatible = "riscv,cpu-intc"; @@ -104,6 +178,30 @@ d-cache-sets = <512>; next-level-cache = <&l2_cache>; mmu-type = "riscv,sv39"; + cpu-freq = "1.848Ghz"; + cpu-cacheline = "64Bytes"; + + operating-points = < + /* kHz uV */ + 300000 600000 + 800000 700000 + 1500000 800000 + 1848000 1000000 + >; + light,dvddm-operating-points = < + /* kHz uV */ + 300000 750000 + 800000 800000 + 1500000 800000 + 1848000 1000000 + >; + clock-latency = <61036>; + clocks = <&clk C910_CCLK>, + <&clk C910_CCLK_I0>, + <&clk CPU_PLL1_FOUTPOSTDIV>, + <&clk CPU_PLL0_FOUTPOSTDIV>; + clock-names = "c910_cclk", "c910_cclk_i0", + "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; cpu3_intc: interrupt-controller { compatible = "riscv,cpu-intc"; @@ -121,17 +219,26 @@ cache-unified; }; }; + + osc_32k: clock-osc-32k { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "osc_32k"; + }; - osc: oscillator { + osc_24m: clock-osc-24m { compatible = "fixed-clock"; - clock-output-names = "osc_24m"; #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "osc_24m"; }; - osc_32k: 32k-oscillator { + rc_24m: clock-rc-24m { compatible = "fixed-clock"; - clock-output-names = "osc_32k"; #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "rc_24m"; }; apb_clk: apb-clk-clock { @@ -443,7 +550,22 @@ compatible = "thead,th1520-pwm"; reg = <0xff 0xec01c000 0x0 0x4000>; #pwm-cells = <3>; - clocks = <&osc>; + clocks = <&osc_24m>; + }; + + clk: clock-controller@ffef010000 { + compatible = "thead,light-fm-ree-clk"; + reg = <0xff 0xef010000 0x0 0x1000>; + #clock-cells = <1>; + clocks = <&osc_32k>, <&osc_24m>, <&rc_24m>; + clock-names = "osc_32k", "osc_24m", "rc_24m"; + status = "okay"; + }; + + sys_reg: sys_reg@ffef010100 { + compatible = "thead,light_sys_reg"; + reg = <0xff 0xef010100 0x0 0x100>; + status = "okay"; }; misc_sysreg: misc_sysreg@ffec02c000 { @@ -680,5 +802,20 @@ interrupts = <55 IRQ_TYPE_LEVEL_HIGH>; }; }; + + mbox_910t: mbox@ffffc38000 { + compatible = "thead,light-mbox"; + reg = <0xff 0xffc38000 0x0 0x4000>, + <0xff 0xffc44000 0x0 0x1000>, + <0xff 0xffc4c000 0x0 0x1000>, + <0xff 0xffc54000 0x0 0x1000>; + reg-names = "local_base", "remote_icu0", "remote_icu1", "remote_icu2"; + #interrupt-cells = <2>; + interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&apb_clk>; + clock-names = "ipg"; + icu_cpu_id = <0>; + #mbox-cells = <2>; + }; }; }; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c30099866174d3..1578cc32432dca 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -501,6 +501,7 @@ source "drivers/clk/visconti/Kconfig" source "drivers/clk/x86/Kconfig" source "drivers/clk/xilinx/Kconfig" source "drivers/clk/zynqmp/Kconfig" +source "drivers/clk/thead/Kconfig" # Kunit test cases config CLK_KUNIT_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 18969cbd4bb1e8..abaccd67095124 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -136,3 +136,4 @@ endif obj-y += xilinx/ obj-$(CONFIG_ARCH_ZYNQ) += zynq/ obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/ +obj-$(CONFIG_ARCH_THEAD) += thead/ diff --git a/drivers/clk/thead/Kconfig b/drivers/clk/thead/Kconfig new file mode 100644 index 00000000000000..4fa0021a195d27 --- /dev/null +++ b/drivers/clk/thead/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 + +config THEAD_CLK + bool + def_bool ARCH_THEAD + +config CLK_LIGHT_MPW + bool "Thead Light MPW Clock Driver" + depends on ARCH_THEAD + default n + help + Build the driver for light mpw Clock Driver + +config CLK_LIGHT_FM + bool "Thead Light Fullmask Clock Driver" + depends on ARCH_THEAD + default n + help + Build the driver for light fullmask Clock Driver diff --git a/drivers/clk/thead/Makefile b/drivers/clk/thead/Makefile new file mode 100644 index 00000000000000..24a349f919890f --- /dev/null +++ b/drivers/clk/thead/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_THEAD_CLK) += \ + clk.o + +obj-$(CONFIG_CLK_LIGHT_MPW) += clk-light-mpw.o +obj-$(CONFIG_CLK_LIGHT_FM) += clk-light-fm.o +obj-$(CONFIG_CLK_LIGHT_FM) += gate/ diff --git a/drivers/clk/thead/clk-light-fm.c b/drivers/clk/thead/clk-light-fm.c new file mode 100644 index 00000000000000..2fe47c063a5370 --- /dev/null +++ b/drivers/clk/thead/clk-light-fm.c @@ -0,0 +1,646 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static struct clk *clks[CLK_END]; +static struct clk_onecell_data clk_data; + +/* Light Fullmask */ +static u32 share_cnt_x2h_cpusys_clk_en; +static u32 share_cnt_dmac_cpusys_clk_en; +static u32 share_cnt_timer0_clk_en; +static u32 share_cnt_timer1_clk_en; +static u32 share_cnt_axi4_cpusys2_clk_en; +static u32 share_cnt_bmu_c910_clk_en; +static u32 share_cnt_aon2cpu_a2x_clk_en; +static u32 share_cnt_chip_dbg_clk_en; +static u32 share_cnt_x2x_cpusys_clk_en; +static u32 share_cnt_cfg2tee_x2h_clk_en; +static u32 share_cnt_cpu2aon_x2h_clk_en; +static u32 share_cnt_cpu2vp_x2p_clk_en; +static u32 share_cnt_npu_core_clk_en; +static u32 share_cnt_cpu2peri_x2h_clk_en; +static u32 share_cnt_cpu2vi_x2h_clk_en; +static u32 share_cnt_vpsys_axi_aclk_en; +static u32 share_cnt_gmac1_clk_en; +static u32 share_cnt_gmac0_clk_en; +static u32 share_cnt_perisys_apb3_hclk_en; +static u32 share_cnt_qspi0_clk_en; +static u32 share_cnt_gmac_axi_clk_en; +static u32 share_cnt_gpio0_clk_en; +static u32 share_cnt_gpio1_clk_en; +static u32 share_cnt_pwm_clk_en; +static u32 share_cnt_spi_clk_en; +static u32 share_cnt_uart0_clk_en; +static u32 share_cnt_uart2_clk_en; +static u32 share_cnt_i2c2_clk_en; +static u32 share_cnt_peri_i2s_clk_en; +static u32 share_cnt_qspi1_clk_en; +static u32 share_cnt_uart1_clk_en; +static u32 share_cnt_uart3_clk_en; +static u32 share_cnt_uart4_clk_en; +static u32 share_cnt_uart5_clk_en; +static u32 share_cnt_i2c0_clk_en; +static u32 share_cnt_i2c1_clk_en; +static u32 share_cnt_i2c4_clk_en; +static u32 share_cnt_i2c5_clk_en; +static u32 share_cnt_gpio2_clk_en; +static u32 share_cnt_gpio3_clk_en; +static u32 share_cnt_vosys_axi_aclk_en; + +/* Light Fullmask PLL Bypass */ +static const char * const cpu_pll0_bypass_sels[] = {"cpu_pll0_foutpostdiv", "osc_24m", }; +static const char * const cpu_pll1_bypass_sels[] = {"cpu_pll1_foutpostdiv", "osc_24m", }; +static const char * const gmac_pll_bypass_sels[] = {"gmac_pll_foutpostdiv", "osc_24m", }; +static const char * const video_pll_bypass_sels[] = {"video_pll_foutpostdiv", "osc_24m", }; +static const char * const tee_pll_bypass_sels[] = {"tee_pll_foutpostdiv", "osc_24m"}; +static const char * const dpu0_pll_bypass_sels[] = {"dpu0_pll_foutpostdiv", "osc_24m"}; +static const char * const dpu1_pll_bypass_sels[] = {"dpu1_pll_foutpostdiv", "osc_24m"}; + +/* light fullmask mux */ +static const char * const ahb2_cpusys_hclk_sels[] = {"ahb2_cpusys_hclk_out_div", "osc_24m"}; +static const char * const c910_cclk_i0_sels[] = {"cpu_pll0_foutpostdiv", "osc_24m"}; +static const char * const c910_cclk_sels[] = {"c910_cclk_i0", "cpu_pll1_foutpostdiv"}; +static const char * const cfg_axi_aclk_sels[] = {"cfg_axi_aclk_out_div", "osc_24m"}; +static const char * const teesys_hclk_sels[] = {"teesys_i1_hclk", "teesys_i0_hclk"}; +static const char * const perisys_ahb_hclk_sels[] = {"perisys_ahb_hclk_out_div", "osc_24m"}; +static const char * const clk_out_1_sels[] = {"osc_24m", "clk_out_1_out_div"}; +static const char * const clk_out_2_sels[] = {"osc_24m", "clk_out_2_out_div"}; +static const char * const clk_out_3_sels[] = {"osc_24m", "clk_out_3_out_div"}; +static const char * const clk_out_4_sels[] = {"osc_24m", "clk_out_4_out_div"}; +static const char * const peri_i2s_src_clk_sels[] = {"clkgen_peri_i2s_src_clk_0", "clkgen_peri_i2s_src_clk_1"}; +static const char * const npu_cclk_sels[] = {"gmac_pll_foutpostdiv", "npu_cclk_out_div"}; +static const char * const cfg_apb_pclk_sels[] = {"cfg_apb_pclk_out_div", "osc_24m"}; +static const char * const uart_sclk_sels[] = {"clk_100m", "osc_24m"}; + +static const struct light_pll_rate_table light_cpupll_tbl[] = { + LIGHT_PLL_RATE(2616000000U, 2616000000U, 1, 109, 0, 1, 1), + LIGHT_PLL_RATE(2592000000U, 2592000000U, 1, 108, 0, 1, 1), + LIGHT_PLL_RATE(2568000000U, 2568000000U, 1, 107, 0, 1, 1), + LIGHT_PLL_RATE(2544000000U, 2544000000U, 1, 106, 0, 1, 1), + LIGHT_PLL_RATE(2520000000U, 2520000000U, 1, 105, 0, 1, 1), + LIGHT_PLL_RATE(2496000000U, 2496000000U, 1, 104, 0, 1, 1), + LIGHT_PLL_RATE(2472000000U, 2472000000U, 1, 103, 0, 1, 1), + LIGHT_PLL_RATE(2448000000U, 2448000000U, 1, 102, 0, 1, 1), + LIGHT_PLL_RATE(2424000000U, 2424000000U, 1, 101, 0, 1, 1), + LIGHT_PLL_RATE(2400000000U, 2400000000U, 1, 100, 0, 1, 1), + LIGHT_PLL_RATE(2376000000U, 2376000000U, 1, 99, 0, 1, 1), + LIGHT_PLL_RATE(2352000000U, 2352000000U, 1, 98, 0, 1, 1), + LIGHT_PLL_RATE(2328000000U, 2328000000U, 1, 97, 0, 1, 1), + LIGHT_PLL_RATE(2304000000U, 2304000000U, 1, 96, 0, 1, 1), + LIGHT_PLL_RATE(2280000000U, 2280000000U, 1, 95, 0, 1, 1), + LIGHT_PLL_RATE(2256000000U, 2256000000U, 1, 94, 0, 1, 1), + LIGHT_PLL_RATE(2232000000U, 2232000000U, 1, 93, 0, 1, 1), + LIGHT_PLL_RATE(2208000000U, 2208000000U, 1, 92, 0, 1, 1), + LIGHT_PLL_RATE(2184000000U, 2184000000U, 1, 91, 0, 1, 1), + LIGHT_PLL_RATE(2160000000U, 2160000000U, 1, 90, 0, 1, 1), + LIGHT_PLL_RATE(2136000000U, 2136000000U, 1, 89, 0, 1, 1), + LIGHT_PLL_RATE(2112000000U, 2112000000U, 1, 88, 0, 1, 1), + LIGHT_PLL_RATE(2088000000U, 2088000000U, 1, 87, 0, 1, 1), + LIGHT_PLL_RATE(2064000000U, 2064000000U, 1, 86, 0, 1, 1), + LIGHT_PLL_RATE(2040000000U, 2040000000U, 1, 85, 0, 1, 1), + LIGHT_PLL_RATE(2016000000U, 2016000000U, 1, 84, 0, 1, 1), + LIGHT_PLL_RATE(1992000000U, 1992000000U, 1, 83, 0, 1, 1), + LIGHT_PLL_RATE(1968000000U, 1968000000U, 1, 82, 0, 1, 1), + LIGHT_PLL_RATE(1944000000U, 1944000000U, 1, 81, 0, 1, 1), + LIGHT_PLL_RATE(1920000000U, 1920000000U, 1, 80, 0, 1, 1), + LIGHT_PLL_RATE(1896000000U, 1896000000U, 1, 79, 0, 1, 1), + LIGHT_PLL_RATE(1872000000U, 1872000000U, 1, 78, 0, 1, 1), + LIGHT_PLL_RATE(1848000000U, 1848000000U, 1, 77, 0, 1, 1), + LIGHT_PLL_RATE(1824000000U, 1824000000U, 1, 76, 0, 1, 1), + LIGHT_PLL_RATE(1800000000U, 1800000000U, 1, 75, 0, 1, 1), + LIGHT_PLL_RATE(1776000000U, 1776000000U, 1, 74, 0, 1, 1), + LIGHT_PLL_RATE(1752000000U, 1752000000U, 1, 73, 0, 1, 1), + LIGHT_PLL_RATE(1728000000U, 1728000000U, 1, 72, 0, 1, 1), + LIGHT_PLL_RATE(1704000000U, 1704000000U, 1, 71, 0, 1, 1), + LIGHT_PLL_RATE(1680000000U, 1680000000U, 1, 70, 0, 1, 1), + LIGHT_PLL_RATE(1656000000U, 1656000000U, 1, 69, 0, 1, 1), + LIGHT_PLL_RATE(1632000000U, 1632000000U, 1, 68, 0, 1, 1), + LIGHT_PLL_RATE(1608000000U, 1608000000U, 1, 67, 0, 1, 1), + LIGHT_PLL_RATE(1584000000U, 1584000000U, 1, 66, 0, 1, 1), + LIGHT_PLL_RATE(1560000000U, 1560000000U, 1, 65, 0, 1, 1), + LIGHT_PLL_RATE(1536000000U, 1536000000U, 1, 64, 0, 1, 1), + LIGHT_PLL_RATE(1512000000U, 1512000000U, 1, 63, 0, 1, 1), + LIGHT_PLL_RATE(3000000000U, 1500000000U, 1, 125, 0, 2, 1), + LIGHT_PLL_RATE(2976000000U, 1488000000U, 1, 124, 0, 2, 1), + LIGHT_PLL_RATE(2952000000U, 1476000000U, 1, 123, 0, 2, 1), + LIGHT_PLL_RATE(2928000000U, 1464000000U, 1, 122, 0, 2, 1), + LIGHT_PLL_RATE(2904000000U, 1452000000U, 1, 121, 0, 2, 1), + LIGHT_PLL_RATE(2880000000U, 1440000000U, 1, 120, 0, 2, 1), + LIGHT_PLL_RATE(2856000000U, 1428000000U, 1, 119, 0, 2, 1), + LIGHT_PLL_RATE(2832000000U, 1416000000U, 1, 118, 0, 2, 1), + LIGHT_PLL_RATE(2808000000U, 1404000000U, 1, 117, 0, 2, 1), + LIGHT_PLL_RATE(2784000000U, 1392000000U, 1, 116, 0, 2, 1), + LIGHT_PLL_RATE(2760000000U, 1380000000U, 1, 115, 0, 2, 1), + LIGHT_PLL_RATE(2736000000U, 1368000000U, 1, 114, 0, 2, 1), + LIGHT_PLL_RATE(2712000000U, 1356000000U, 1, 113, 0, 2, 1), + LIGHT_PLL_RATE(2688000000U, 1344000000U, 1, 112, 0, 2, 1), + LIGHT_PLL_RATE(2664000000U, 1332000000U, 1, 111, 0, 2, 1), + LIGHT_PLL_RATE(2640000000U, 1320000000U, 1, 110, 0, 2, 1), + LIGHT_PLL_RATE(2616000000U, 1308000000U, 1, 109, 0, 2, 1), + LIGHT_PLL_RATE(2592000000U, 1296000000U, 1, 108, 0, 2, 1), + LIGHT_PLL_RATE(2568000000U, 1284000000U, 1, 107, 0, 2, 1), + LIGHT_PLL_RATE(2544000000U, 1272000000U, 1, 106, 0, 2, 1), + LIGHT_PLL_RATE(2520000000U, 1260000000U, 1, 105, 0, 2, 1), + LIGHT_PLL_RATE(2496000000U, 1248000000U, 1, 104, 0, 2, 1), + LIGHT_PLL_RATE(2472000000U, 1236000000U, 1, 103, 0, 2, 1), + LIGHT_PLL_RATE(2448000000U, 1224000000U, 1, 102, 0, 2, 1), + LIGHT_PLL_RATE(2424000000U, 1212000000U, 1, 101, 0, 2, 1), + LIGHT_PLL_RATE(2400000000U, 1200000000U, 1, 100, 0, 2, 1), + LIGHT_PLL_RATE(2376000000U, 1188000000U, 1, 99, 0, 2, 1), + LIGHT_PLL_RATE(2352000000U, 1176000000U, 1, 98, 0, 2, 1), + LIGHT_PLL_RATE(2328000000U, 1164000000U, 1, 97, 0, 2, 1), + LIGHT_PLL_RATE(2304000000U, 1152000000U, 1, 96, 0, 2, 1), + LIGHT_PLL_RATE(2280000000U, 1140000000U, 1, 95, 0, 2, 1), + LIGHT_PLL_RATE(2256000000U, 1128000000U, 1, 94, 0, 2, 1), + LIGHT_PLL_RATE(2232000000U, 1116000000U, 1, 93, 0, 2, 1), + LIGHT_PLL_RATE(2208000000U, 1104000000U, 1, 92, 0, 2, 1), + LIGHT_PLL_RATE(2184000000U, 1092000000U, 1, 91, 0, 2, 1), + LIGHT_PLL_RATE(2160000000U, 1080000000U, 1, 90, 0, 2, 1), + LIGHT_PLL_RATE(2136000000U, 1068000000U, 1, 89, 0, 2, 1), + LIGHT_PLL_RATE(2112000000U, 1056000000U, 1, 88, 0, 2, 1), + LIGHT_PLL_RATE(2088000000U, 1044000000U, 1, 87, 0, 2, 1), + LIGHT_PLL_RATE(2064000000U, 1032000000U, 1, 86, 0, 2, 1), + LIGHT_PLL_RATE(2040000000U, 1020000000U, 1, 85, 0, 2, 1), + LIGHT_PLL_RATE(2016000000U, 1008000000U, 1, 84, 0, 2, 1), + LIGHT_PLL_RATE(3000000000U, 1000000000U, 1, 125, 0, 3, 1), + LIGHT_PLL_RATE(2976000000U, 992000000U, 1, 124, 0, 3, 1), + LIGHT_PLL_RATE(2952000000U, 984000000U, 1, 123, 0, 3, 1), + LIGHT_PLL_RATE(2928000000U, 976000000U, 1, 122, 0, 3, 1), + LIGHT_PLL_RATE(2904000000U, 968000000U, 1, 121, 0, 3, 1), + LIGHT_PLL_RATE(2880000000U, 960000000U, 1, 120, 0, 3, 1), + LIGHT_PLL_RATE(2856000000U, 952000000U, 1, 119, 0, 3, 1), + LIGHT_PLL_RATE(2832000000U, 944000000U, 1, 118, 0, 3, 1), + LIGHT_PLL_RATE(2808000000U, 936000000U, 1, 117, 0, 3, 1), + LIGHT_PLL_RATE(2784000000U, 928000000U, 1, 116, 0, 3, 1), + LIGHT_PLL_RATE(2760000000U, 920000000U, 1, 115, 0, 3, 1), + LIGHT_PLL_RATE(2736000000U, 912000000U, 1, 114, 0, 3, 1), + LIGHT_PLL_RATE(2712000000U, 904000000U, 1, 113, 0, 3, 1), + LIGHT_PLL_RATE(1800000000U, 900000000U, 1, 75, 0, 2, 1), + LIGHT_PLL_RATE(2688000000U, 896000000U, 1, 112, 0, 3, 1), + LIGHT_PLL_RATE(2664000000U, 888000000U, 1, 111, 0, 3, 1), + LIGHT_PLL_RATE(2640000000U, 880000000U, 1, 110, 0, 3, 1), + LIGHT_PLL_RATE(2616000000U, 872000000U, 1, 109, 0, 3, 1), + LIGHT_PLL_RATE(2592000000U, 864000000U, 1, 108, 0, 3, 1), + LIGHT_PLL_RATE(2568000000U, 856000000U, 1, 107, 0, 3, 1), + LIGHT_PLL_RATE(2544000000U, 848000000U, 1, 106, 0, 3, 1), + LIGHT_PLL_RATE(2520000000U, 840000000U, 1, 105, 0, 3, 1), + LIGHT_PLL_RATE(2496000000U, 832000000U, 1, 104, 0, 3, 1), + LIGHT_PLL_RATE(2472000000U, 824000000U, 1, 103, 0, 3, 1), + LIGHT_PLL_RATE(2448000000U, 816000000U, 1, 102, 0, 3, 1), + LIGHT_PLL_RATE(2424000000U, 808000000U, 1, 101, 0, 3, 1), + LIGHT_PLL_RATE(2400000000U, 800000000U, 1, 100, 0, 3, 1), + LIGHT_PLL_RATE(2376000000U, 792000000U, 1, 99, 0, 3, 1), + LIGHT_PLL_RATE(2352000000U, 784000000U, 1, 98, 0, 3, 1), + LIGHT_PLL_RATE(2328000000U, 776000000U, 1, 97, 0, 3, 1), + LIGHT_PLL_RATE(2304000000U, 768000000U, 1, 96, 0, 3, 1), + LIGHT_PLL_RATE(2280000000U, 760000000U, 1, 95, 0, 3, 1), + LIGHT_PLL_RATE(2256000000U, 752000000U, 1, 94, 0, 3, 1), + LIGHT_PLL_RATE(2232000000U, 744000000U, 1, 93, 0, 3, 1), + LIGHT_PLL_RATE(2208000000U, 736000000U, 1, 92, 0, 3, 1), + LIGHT_PLL_RATE(2184000000U, 728000000U, 1, 91, 0, 3, 1), + LIGHT_PLL_RATE(2160000000U, 720000000U, 1, 90, 0, 3, 1), + LIGHT_PLL_RATE(2136000000U, 712000000U, 1, 89, 0, 3, 1), + LIGHT_PLL_RATE(2808000000U, 702000000U, 1, 117, 0, 4, 1), + LIGHT_PLL_RATE(2760000000U, 690000000U, 1, 115, 0, 4, 1), + LIGHT_PLL_RATE(2712000000U, 678000000U, 1, 113, 0, 4, 1), + LIGHT_PLL_RATE(2664000000U, 666000000U, 1, 111, 0, 4, 1), + LIGHT_PLL_RATE(2616000000U, 654000000U, 1, 109, 0, 4, 1), + LIGHT_PLL_RATE(2568000000U, 642000000U, 1, 107, 0, 4, 1), + LIGHT_PLL_RATE(2520000000U, 630000000U, 1, 105, 0, 4, 1), + LIGHT_PLL_RATE(2472000000U, 618000000U, 1, 103, 0, 4, 1), + LIGHT_PLL_RATE(2424000000U, 606000000U, 1, 101, 0, 4, 1), + LIGHT_PLL_RATE(3000000000U, 600000000U, 1, 125, 0, 5, 1), + LIGHT_PLL_RATE(2952000000U, 590400000U, 1, 123, 0, 5, 1), + LIGHT_PLL_RATE(2904000000U, 580800000U, 1, 121, 0, 5, 1), + LIGHT_PLL_RATE(2856000000U, 571200000U, 1, 119, 0, 5, 1), + LIGHT_PLL_RATE(2808000000U, 561600000U, 1, 117, 0, 5, 1), + LIGHT_PLL_RATE(2760000000U, 552000000U, 1, 115, 0, 5, 1), + LIGHT_PLL_RATE(2712000000U, 542400000U, 1, 113, 0, 5, 1), + LIGHT_PLL_RATE(2664000000U, 532800000U, 1, 111, 0, 5, 1), + LIGHT_PLL_RATE(2616000000U, 523200000U, 1, 109, 0, 5, 1), + LIGHT_PLL_RATE(2568000000U, 513600000U, 1, 107, 0, 5, 1), + LIGHT_PLL_RATE(2520000000U, 504000000U, 1, 105, 0, 5, 1), + LIGHT_PLL_RATE(3000000000U, 500000000U, 1, 125, 0, 6, 1), + LIGHT_PLL_RATE(2952000000U, 492000000U, 1, 123, 0, 6, 1), + LIGHT_PLL_RATE(2904000000U, 484000000U, 1, 121, 0, 6, 1), + LIGHT_PLL_RATE(2856000000U, 476000000U, 1, 119, 0, 6, 1), + LIGHT_PLL_RATE(2808000000U, 468000000U, 1, 117, 0, 6, 1), + LIGHT_PLL_RATE(2760000000U, 460000000U, 1, 115, 0, 6, 1), + LIGHT_PLL_RATE(2712000000U, 452000000U, 1, 113, 0, 6, 1), + LIGHT_PLL_RATE(2664000000U, 444000000U, 1, 111, 0, 6, 1), + LIGHT_PLL_RATE(2616000000U, 436000000U, 1, 109, 0, 6, 1), + LIGHT_PLL_RATE(2568000000U, 428000000U, 1, 107, 0, 6, 1), + LIGHT_PLL_RATE(2520000000U, 420000000U, 1, 105, 0, 6, 1), + LIGHT_PLL_RATE(2472000000U, 412000000U, 1, 103, 0, 6, 1), + LIGHT_PLL_RATE(2400000000U, 400000000U, 1, 100, 0, 3, 2), + LIGHT_PLL_RATE(2352000000U, 392000000U, 1, 98, 0, 3, 2), + LIGHT_PLL_RATE(2304000000U, 384000000U, 1, 96, 0, 3, 2), + LIGHT_PLL_RATE(2256000000U, 376000000U, 1, 94, 0, 3, 2), + LIGHT_PLL_RATE(2208000000U, 368000000U, 1, 92, 0, 3, 2), + LIGHT_PLL_RATE(2160000000U, 360000000U, 1, 90, 0, 3, 2), + LIGHT_PLL_RATE(2112000000U, 352000000U, 1, 88, 0, 3, 2), + LIGHT_PLL_RATE(2064000000U, 344000000U, 1, 86, 0, 3, 2), + LIGHT_PLL_RATE(2016000000U, 336000000U, 1, 84, 0, 3, 2), + LIGHT_PLL_RATE(1968000000U, 328000000U, 1, 82, 0, 3, 2), + LIGHT_PLL_RATE(1920000000U, 320000000U, 1, 80, 0, 3, 2), + LIGHT_PLL_RATE(1872000000U, 312000000U, 1, 78, 0, 3, 2), + LIGHT_PLL_RATE(1824000000U, 304000000U, 1, 76, 0, 3, 2), + LIGHT_PLL_RATE(3000000000U, 300000000U, 1, 125, 0, 5, 2), + LIGHT_PLL_RATE(2880000000U, 288000000U, 1, 120, 0, 5, 2), + LIGHT_PLL_RATE(2760000000U, 276000000U, 1, 115, 0, 5, 2), + LIGHT_PLL_RATE(2640000000U, 264000000U, 1, 110, 0, 5, 2), + LIGHT_PLL_RATE(2520000000U, 252000000U, 1, 105, 0, 5, 2), + LIGHT_PLL_RATE(2400000000U, 240000000U, 1, 100, 0, 5, 2), + LIGHT_PLL_RATE(2280000000U, 228000000U, 1, 95, 0, 5, 2), + LIGHT_PLL_RATE(2160000000U, 216000000U, 1, 90, 0, 5, 2), + LIGHT_PLL_RATE(2040000000U, 204000000U, 1, 85, 0, 5, 2), + LIGHT_PLL_RATE(3000000000U, 200000000U, 1, 125, 0, 5, 3), + LIGHT_PLL_RATE(2880000000U, 192000000U, 1, 120, 0, 5, 3), + LIGHT_PLL_RATE(2760000000U, 184000000U, 1, 115, 0, 5, 3), + LIGHT_PLL_RATE(2640000000U, 176000000U, 1, 110, 0, 5, 3), + LIGHT_PLL_RATE(2520000000U, 168000000U, 1, 105, 0, 5, 3), + LIGHT_PLL_RATE(2400000000U, 160000000U, 1, 100, 0, 5, 3), + LIGHT_PLL_RATE(2280000000U, 152000000U, 1, 95, 0, 5, 3), + LIGHT_PLL_RATE(2160000000U, 144000000U, 1, 90, 0, 5, 3), + LIGHT_PLL_RATE(2040000000U, 136000000U, 1, 85, 0, 5, 3), + LIGHT_PLL_RATE(1920000000U, 128000000U, 1, 80, 0, 5, 3), + LIGHT_PLL_RATE(3000000000U, 125000000U, 1, 125, 0, 6, 4), + LIGHT_PLL_RATE(2760000000U, 115000000U, 1, 115, 0, 6, 4), + LIGHT_PLL_RATE(2520000000U, 105000000U, 1, 105, 0, 6, 4), + LIGHT_PLL_RATE(2280000000U, 95000000U, 1, 95, 0, 6, 4), + LIGHT_PLL_RATE(2040000000U, 85000000U, 1, 85, 0, 6, 4), + LIGHT_PLL_RATE(1800000000U, 75000000U, 1, 75, 0, 6, 4), + LIGHT_PLL_RATE(1560000000U, 65000000U, 1, 65, 0, 6, 4), + LIGHT_PLL_RATE(1320000000U, 55000000U, 1, 55, 0, 6, 4), +}; + +static const struct light_pll_rate_table light_dpupll_tbl[] = { + LIGHT_PLL_RATE(2376000000U, 1188000000U, 1, 99, 0, 2, 1), + LIGHT_PLL_RATE(1980000000U, 990000000U, 2, 165, 0, 2, 1), + LIGHT_PLL_RATE(2970000000U, 742500000U, 4, 495, 0, 4, 1), + LIGHT_PLL_RATE(2304000000U, 1152000000U, 1, 96, 0, 2, 1), + LIGHT_PLL_RATE(1512000000U, 504000000U, 1, 63, 0, 3, 1), + LIGHT_PLL_RATE(1512000000U, 503500000U, 1, 63, 0, 3, 1), + LIGHT_PLL_RATE(2898000000U, 483000000U, 4, 483, 0, 6, 1), + LIGHT_PLL_RATE(2592000000U, 648000000U, 1, 108, 0, 4, 1), + LIGHT_PLL_RATE(2772000000U, 924000000U, 2, 231, 0, 3, 1), + LIGHT_PLL_RATE(2856000000U, 476000000U, 1, 119, 0, 6, 1), + LIGHT_PLL_RATE(2130000000U, 355000000U, 4, 355, 0, 6, 1), + LIGHT_PLL_RATE(3192000000U, 456000000U, 1, 133, 0, 7, 1), + LIGHT_PLL_RATE(2730000000U, 390000000U, 4, 455, 0, 7, 1), + LIGHT_PLL_RATE(1680000000U, 240000000U, 1, 70, 0, 7, 1), + LIGHT_PLL_RATE(2832000000U, 708000000U, 1, 118, 0, 4, 1), + LIGHT_PLL_RATE(1026000000U, 342000000U, 4, 171, 0, 3, 1), + LIGHT_PLL_RATE(1260000000U, 630000000U, 4, 210, 0, 2, 1), +}; + +static struct light_pll_clk light_cpu_pll0div = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_CPU_PLL0, + .rate_table = light_cpupll_tbl, + .rate_count = ARRAY_SIZE(light_cpupll_tbl), +}; + +static struct light_pll_clk light_cpu_pll1div = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_CPU_PLL1, + .rate_table = light_cpupll_tbl, + .rate_count = ARRAY_SIZE(light_cpupll_tbl), +}; + +static struct light_pll_clk light_dpu0_plldiv = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_DPU0_PLL, + .rate_table = light_dpupll_tbl, + .rate_count = ARRAY_SIZE(light_dpupll_tbl), +}; + +static struct light_pll_clk light_dpu1_plldiv = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_DPU1_PLL, + .rate_table = light_dpupll_tbl, + .rate_count = ARRAY_SIZE(light_dpupll_tbl), +}; + +static int light_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *ap_base; + int ret; + const bool *teesys = of_device_get_match_data(dev); + + /* Clock source */ + clks[CLK_DUMMY] = thead_clk_fixed("dummy", 0); + clks[OSC_32K] = of_clk_get_by_name(np, "osc_32k"); + clks[OSC_24M] = of_clk_get_by_name(np, "osc_24m"); + clks[RC_24M] = of_clk_get_by_name(np, "rc_24m"); + + np = dev->of_node; + ap_base = devm_platform_ioremap_resource(pdev, 0); + if (WARN_ON(IS_ERR(ap_base))) { + ret = PTR_ERR(ap_base); + goto unregister_clks; + } + + /* Light Fullmask AP PLL clocks */ + clks[CPU_PLL0_FOUTPOSTDIV] = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); + clks[CPU_PLL1_FOUTPOSTDIV] = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); + + clks[DPU0_PLL_FOUTPOSTDIV] = thead_light_pll("dpu0_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu0_plldiv); + clks[DPU1_PLL_FOUTPOSTDIV] = thead_light_pll("dpu1_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu1_plldiv); + + /* Light Fullmask AP Fixed PLL */ + clks[GMAC_PLL_FOUTPOSTDIV] = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); + clks[VIDEO_PLL_FOUTPOSTDIV] = thead_clk_fixed("video_pll_foutpostdiv", 792000000); + clks[VIDEO_PLL_FOUTVCO] = thead_clk_fixed("video_pll_foutvco", 2376000000); + clks[TEE_PLL_FOUTPOSTDIV] = thead_clk_fixed("tee_pll_foutpostdiv", 792000000); + clks[CLKGEN_PERI_I2S_SRC_CLK_0] = thead_clk_fixed("clkgen_peri_i2s_src_clk_0", 294912000); //from audio_pll_foutpostdiv + clks[CLKGEN_PERI_I2S_SRC_CLK_1] = thead_clk_fixed("clkgen_peri_i2s_src_clk_1", 135475200); //from sys_pll_foutpostdiv + clks[CLKGEN_C910_BUS_CLK_NO_ICG] = thead_clk_fixed("clkgen_c910_bus_clk_no_icg", 750000000); + clks[AONSYS_BUS_CLK] = thead_clk_fixed("aonsys_hclk", 101606400); //from sys_pll, maybe change ? + + /* Light Fullmask AP MUX */ + clks[CPU_PLL0_BYPASS] = thead_light_clk_mux_flags("cpu_pll0_bypass", ap_base + 0x4, 30, 1, cpu_pll0_bypass_sels, ARRAY_SIZE(cpu_pll0_bypass_sels), CLK_SET_RATE_PARENT); + clks[CPU_PLL1_BYPASS] = thead_light_clk_mux_flags("cpu_pll1_bypass", ap_base + 0x14, 30, 1, cpu_pll1_bypass_sels, ARRAY_SIZE(cpu_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[GMAC_PLL_BYPASS] = thead_light_clk_mux_flags("gmac_pll_bypass", ap_base + 0x24, 30, 1, gmac_pll_bypass_sels, ARRAY_SIZE(gmac_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[VIDEO_PLL_BYPASS] = thead_light_clk_mux_flags("video_pll_bypass", ap_base + 0x34, 30, 1, video_pll_bypass_sels, ARRAY_SIZE(video_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[TEE_PLL_BYPASS] = thead_light_clk_mux_flags("tee_pll_bypass", ap_base + 0x64, 30, 1, tee_pll_bypass_sels, ARRAY_SIZE(tee_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[DPU0_PLL_BYPASS] = thead_light_clk_mux_flags("dpu0_pll_bypass", ap_base + 0x44, 30, 1, dpu0_pll_bypass_sels, ARRAY_SIZE(dpu0_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[DPU1_PLL_BYPASS] = thead_light_clk_mux_flags("dpu1_pll_bypass", ap_base + 0x54, 30, 1, dpu1_pll_bypass_sels, ARRAY_SIZE(dpu1_pll_bypass_sels), CLK_SET_RATE_PARENT); + + clks[AHB2_CPUSYS_HCLK] = thead_light_clk_mux_flags("ahb2_cpusys_hclk", ap_base + 0x120, 5, 1, ahb2_cpusys_hclk_sels, ARRAY_SIZE(ahb2_cpusys_hclk_sels), CLK_SET_RATE_PARENT); + clks[C910_CCLK_I0] = thead_light_clk_mux_flags("c910_cclk_i0", ap_base + 0x100, 1, 1, c910_cclk_i0_sels, ARRAY_SIZE(c910_cclk_i0_sels), CLK_SET_RATE_PARENT); + clks[C910_CCLK] = thead_light_clk_mux_flags("c910_cclk", ap_base + 0x100, 0, 1, c910_cclk_sels, ARRAY_SIZE(c910_cclk_sels), CLK_SET_RATE_PARENT); + clks[CFG_AXI_ACLK] = thead_light_clk_mux_flags("cfg_axi_aclk", ap_base + 0x138, 5, 1, cfg_axi_aclk_sels, ARRAY_SIZE(cfg_axi_aclk_sels), CLK_SET_RATE_PARENT); + + if (teesys) + clks[TEESYS_HCLK] = thead_light_clk_mux_flags("teesys_hclk", ap_base + 0x1cc, 13, 1, teesys_hclk_sels, ARRAY_SIZE(teesys_hclk_sels), CLK_SET_RATE_PARENT); //just for teesys!!! + + clks[PERISYS_AHB_HCLK] = thead_light_clk_mux_flags("perisys_ahb_hclk", ap_base + 0x140, 5, 1, perisys_ahb_hclk_sels, ARRAY_SIZE(perisys_ahb_hclk_sels), CLK_SET_RATE_PARENT); + clks[CLK_OUT_1] = thead_light_clk_mux_flags("clk_out_1", ap_base + 0x1b4, 4, 1, clk_out_1_sels, ARRAY_SIZE(clk_out_1_sels), CLK_SET_RATE_PARENT); + clks[CLK_OUT_2] = thead_light_clk_mux_flags("clk_out_2", ap_base + 0x1b8, 4, 1, clk_out_2_sels, ARRAY_SIZE(clk_out_2_sels), CLK_SET_RATE_PARENT); + clks[CLK_OUT_3] = thead_light_clk_mux_flags("clk_out_3", ap_base + 0x1bc, 4, 1, clk_out_3_sels, ARRAY_SIZE(clk_out_3_sels), CLK_SET_RATE_PARENT); + clks[CLK_OUT_4] = thead_light_clk_mux_flags("clk_out_4", ap_base + 0x1c0, 4, 1, clk_out_4_sels, ARRAY_SIZE(clk_out_4_sels), CLK_SET_RATE_PARENT); + clks[PERI_I2S_SRC_CLK] = thead_light_clk_mux_flags("peri_i2s_src_clk", ap_base + 0x1f0, 0, 1, peri_i2s_src_clk_sels, ARRAY_SIZE(peri_i2s_src_clk_sels), CLK_SET_RATE_PARENT); + clks[NPU_CCLK] = thead_light_clk_mux_flags("npu_cclk", ap_base + 0x1c8, 6, 1, npu_cclk_sels, ARRAY_SIZE(npu_cclk_sels), CLK_SET_RATE_PARENT); + clks[CFG_APB_PCLK] = thead_light_clk_mux_flags("cfg_apb_pclk", ap_base + 0x1c4, 7, 1, cfg_apb_pclk_sels, ARRAY_SIZE(cfg_apb_pclk_sels), CLK_SET_RATE_PARENT); + clks[UART_SCLK] = thead_light_clk_mux_flags("uart_sclk", ap_base + 0x210, 0, 1, uart_sclk_sels, ARRAY_SIZE(uart_sclk_sels), CLK_SET_RATE_PARENT); + + /* Light Fullmask AP Divider */ + clks[AHB2_CPUSYS_HCLK_OUT_DIV] = thead_clk_light_divider("ahb2_cpusys_hclk_out_div", "gmac_pll_fout1ph0", ap_base + 0x120, 0, 3, 4, MUX_TYPE_DIV, 2, 7); + clks[APB3_CPUSYS_PCLK] = thead_clk_light_divider("apb3_cpusys_pclk", "ahb2_cpusys_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); + clks[AXI4_CPUSYS2_ACLK] = thead_clk_light_divider("axi4_cpusys2_aclk", "gmac_pll_foutpostdiv", ap_base + 0x134, 0, 3, 4, MUX_TYPE_DIV, 2, 7); + clks[CFG_AXI_ACLK_OUT_DIV] = thead_clk_light_divider("cfg_axi_aclk_out_div", "video_pll_foutpostdiv", ap_base + 0x138, 0, 4, 4, MUX_TYPE_DIV, 2, 15); + + if (teesys) { + clks[TEESYS_I0_HCLK] = thead_clk_light_divider("teesys_i0_hclk", "tee_pll_foutpostdiv", ap_base + 0x1cc, 0, 4, 4, MUX_TYPE_DIV, 2, 15); //just for teesys!!! + clks[TEESYS_I1_HCLK] = thead_clk_light_divider("teesys_i1_hclk", "video_pll_foutpostdiv", ap_base + 0x1cc, 8, 4, 12, MUX_TYPE_DIV, 2, 15); //just for teesys!!! + } + + clks[PERISYS_AHB_HCLK_OUT_DIV] = thead_clk_light_divider("perisys_ahb_hclk_out_div", "gmac_pll_fout1ph0", ap_base + 0x140, 0, 4, 4, MUX_TYPE_DIV, 2, 7); + clks[PERISYS_APB_PCLK] = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); + clks[PERI2SYS_APB_PCLK] = thead_clk_light_divider("peri2sys_apb_pclk", "gmac_pll_fout4", ap_base + 0x150, 4, 3, 8, MUX_TYPE_DIV, 2, 7); + clks[CLK_OUT_1_OUT_DIV] = thead_clk_light_divider("clk_out_1_out_div", "osc_24m", ap_base + 0x1b4, 0, 3, 3, MUX_TYPE_DIV, 2, 4); + clks[CLK_OUT_2_OUT_DIV] = thead_clk_light_divider("clk_out_2_out_div", "osc_24m", ap_base + 0x1b8, 0, 3, 3, MUX_TYPE_DIV, 2, 4); + clks[CLK_OUT_3_OUT_DIV] = thead_clk_light_divider("clk_out_3_out_div", "osc_24m", ap_base + 0x1bc, 0, 3, 3, MUX_TYPE_DIV, 2, 4); + clks[CLK_OUT_4_OUT_DIV] = thead_clk_light_divider("clk_out_4_out_div", "osc_24m", ap_base + 0x1c0, 0, 3, 3, MUX_TYPE_DIV, 2, 4); + clks[VOSYS_ACLK_M] = thead_clk_light_divider("vosys_aclk_m", "video_pll_foutvco", ap_base + 0x1dc, 0, 4, 4, MUX_TYPE_DIV, 3, 15); + clks[NPU_CCLK_OUT_DIV] = thead_clk_light_divider("npu_cclk_out_div", "video_pll_foutvco", ap_base + 0x1c8, 0, 3, 3, MUX_TYPE_DIV, 3, 7); + clks[CFG_APB_PCLK_OUT_DIV] = thead_clk_light_divider("cfg_apb_pclk_out_div", "gmac_pll_foutpostdiv", ap_base + 0x1c4, 0, 4, 4, MUX_TYPE_DIV, 4, 15); + clks[VISYS_ACLK_M] = thead_clk_light_divider("visys_aclk_m", "video_pll_foutvco", ap_base + 0x1d0, 16, 4, 20, MUX_TYPE_DIV, 3, 15); + clks[VISYS_AHB_HCLK] = thead_clk_light_divider("visys_ahb_hclk", "video_pll_foutvco", ap_base + 0x1d0, 0, 4, 4, MUX_TYPE_DIV, 6, 15); + clks[VPSYS_APB_PCLK] = thead_clk_light_divider("vpsys_apb_pclk", "gmac_pll_fout1ph0", ap_base + 0x1e0, 0, 3, 4, MUX_TYPE_DIV, 2, 7); + clks[VPSYS_AXI_ACLK] = thead_clk_light_divider("vpsys_axi_aclk", "video_pll_foutvco", ap_base + 0x1e0, 8, 4, 12, MUX_TYPE_DIV, 3, 15); + clks[VENC_CCLK] = thead_clk_light_divider("venc_cclk", "gmac_pll_foutpostdiv", ap_base + 0x1e4, 0, 3, 4, MUX_TYPE_DIV, 2, 7); + clks[DPU0_PLL_DIV_CLK] = thead_clk_light_divider("dpu0_pll_div_clk", "dpu0_pll_foutpostdiv", ap_base + 0x1e8, 0, 8, 8, MUX_TYPE_DIV, 2, 214); + clks[DPU1_PLL_DIV_CLK] = thead_clk_light_divider("dpu1_pll_div_clk", "dpu1_pll_foutpostdiv", ap_base + 0x1ec, 0, 8, 8, MUX_TYPE_DIV, 2, 214); + + /* Light Fullmask PLL FOUT */ + clks[GMAC_PLL_FOUT1PH0] = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); + clks[GMAC_PLL_FOUT4] = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); + clks[VIDEO_PLL_FOUT1PH0] = thead_light_clk_fixed_factor("video_pll_fout1ph0", "video_pll_bybass", 1, 2); + clks[VIDEO_PLL_FOUT4] = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); + clks[TEE_PLL_FOUT4] = thead_light_clk_fixed_factor("tee_pll_fout4", "tee_pll_bypass", 1, 8); + clks[CPU_PLL0_FOUT4] = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); + clks[CPU_PLL1_FOUT4] = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); + clks[DPU0_PLL_FOUT4] = thead_light_clk_fixed_factor("dpu0_pll_fout4", "dpu0_pll_bypass", 1, 8); + clks[DPU1_PLL_FOUT4] = thead_light_clk_fixed_factor("dpu1_pll_fout4", "dpu1_pll_bypass", 1, 8); + + /* Light Fullmask Fixed Factor */ + clks[C910_OSC_CLK] = thead_light_clk_fixed_factor("c910_osc_clk", "osc_24m", 1, 1); + clks[QSPI_SSI_CLK] = thead_light_clk_fixed_factor("qspi_ssi_clk", "video_pll_foutpostdiv", 1, 1); /* Note: no mux to select, use default value */ + clks[QSPI0_SSI_CLK] = thead_light_clk_fixed_factor("qspi0_ssi_clk", "qspi_ssi_clk", 1, 1); + clks[QSPI1_SSI_CLK] = thead_light_clk_fixed_factor("qspi1_ssi_clk", "video_pll_fout1ph0", 1, 1); + clks[SPI_SSI_CLK] = thead_light_clk_fixed_factor("spi_ssi_clk", "video_pll_fout1ph0", 1, 1); + clks[EMMC_SDIO_REF_CLK] = thead_light_clk_fixed_factor("emmc_sdio_ref_clk", "video_pll_foutpostdiv", 1, 1); /* Note: no mux to select, use default value */ + clks[PWM_CCLK] = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); + clks[CHIP_DBG_CCLK] = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); + clks[GMAC_CCLK] = thead_light_clk_fixed_factor("gmac_cclk", "gmac_pll_fout1ph0", 1, 1); + clks[GPIO0_DBCLK] = thead_light_clk_fixed_factor("gpio0_dbclk", "pad_rtc_clk", 1, 1); + clks[GPIO1_DBCLK] = thead_light_clk_fixed_factor("gpio1_dbclk", "pad_rtc_clk", 1, 1); + clks[GPIO2_DBCLK] = thead_light_clk_fixed_factor("gpio2_dbclk", "pad_rtc_clk", 1, 1); + clks[GPIO3_DBCLK] = thead_light_clk_fixed_factor("gpio3_dbclk", "pad_rtc_clk", 1, 1); + clks[CLK_100M] = thead_light_clk_fixed_factor("clk_100m", "gmac_pll_foutpostdiv", 1, 10); + clks[I2C_IC_CLK] = thead_light_clk_fixed_factor("i2c_ic_clk", "clk_100m", 1, 2); + clks[TIMER_CCLK] = thead_light_clk_fixed_factor("timer_cclk", "osc_24m", 1, 1); + clks[AXI4_CPUSYS1_ACLK] = thead_light_clk_fixed_factor("axi4_cpusys1_aclk", "clkgen_c910_bus_clk_no_icg", 1, 1); + clks[CPU_BUS_DFTCLK] = thead_light_clk_fixed_factor("cpu_bus_dftclk", "cpu_pll0_foutpostdiv", 1, 2); + clks[CPU_PLL0_TEST_CLK] = thead_light_clk_fixed_factor("cpu_pll0_test_clk", "cpu_pll0_fout4", 1, 8); + clks[CPU_PLL1_TEST_CLK] = thead_light_clk_fixed_factor("cpu_pll1_test_clk", "cpu_pll1_fout4", 1, 8); + clks[DPU0_PLL_TEST_CLK] = thead_light_clk_fixed_factor("dpu0_pll_test_clk", "dpu0_pll_fout4", 1, 8); + clks[DPU1_PLL_TEST_CLK] = thead_light_clk_fixed_factor("dpu1_pll_test_clk", "dpu1_pll_fout4", 1, 8); + clks[GMAC_PLL_TEST_CLK] = thead_light_clk_fixed_factor("gmac_pll_test_clk", "gmac_pll_fout4", 1, 8); + clks[VIDEO_PLL_TEST_CLK] = thead_light_clk_fixed_factor("video_pll_test_clk", "video_pll_fout4", 1, 8); + clks[TEE_PLL_TEST_CLK] = thead_light_clk_fixed_factor("tee_pll_test_clk", "tee_pll_fout4", 1, 8); + clks[AONSYS_BUS_CLK] = thead_light_clk_fixed_factor("aonsys_bus_clk", "aonsys_hclk", 1, 1); + + /* Light Fullmask Clock Gate */ + clks[CLKGEN_AHB2_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x120, 6); + clks[CLKGEN_APB3_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x130, 4); + clks[CLKGEN_C910_BROM_HCLK] = thead_clk_light_gate("clkgen_c910_brom_hclk", "ahb2_cpusys_hclk", ap_base + 0x100, 4); + clks[CLKGEN_SPINLOCK_HCLK] = thead_clk_light_gate("clkgen_spinlock_hclk", "ahb2_cpusys_hclk", ap_base + 0x208, 10); + clks[CLKGEN_MBOX0_PCLK] = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 7); + clks[CLKGEN_MBOX1_PCLK] = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 6); + clks[CLKGEN_MBOX2_PCLK] = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 5); + clks[CLKGEN_MBOX3_PCLK] = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 4); + clks[CLKGEN_WDT0_PCLK] = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 3); + clks[CLKGEN_WDT1_PCLK] = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 2); + + if (teesys) + clks[CLKGEN_MISCSYS_TEE_CCLK] = thead_clk_light_gate("clkgen_miscsys_tee_cclk", "teesys_hclk", ap_base + 0x1cc, 25); //just for teesys!!! + + clks[CLKGEN_SRAM_AXI_ACLK_2] = thead_clk_light_gate("clkgen_sram_axi_aclk_2", "axi4_cpusys1_aclk", ap_base + 0x20c, 2); + clks[CLKGEN_PERISYS_AHB_HCLK] = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x140, 6); + clks[CLKGEN_PERISYS_APB1_HCLK] = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x150, 9); + clks[CLKGEN_PERISYS_APB2_HCLK] = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x150, 10); + clks[CLKGEN_PERISYS_APB4_HCLK] = thead_clk_light_gate("clkgen_perisys_apb4_hclk", "perisys_ahb_hclk", ap_base + 0x150, 12); + clks[CLKGEN_PADCTRL0_APSYS_PCLK] = thead_clk_light_gate("clkgen_padctrl0_apsys_pclk", "perisys_ahb_hclk", ap_base + 0x204, 22); + clks[CLKGEN_DSMART_PCLK] = thead_clk_light_gate("clkgen_dsmart_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 23); + clks[CLKGEN_PADCTRL1_APSYS_PCLK] = thead_clk_light_gate("clkgen_padctrl1_apsys_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 24); + clks[CLKGEN_CLK_OUT_1_CLK] = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x1b4, 5); + clks[CLKGEN_CLK_OUT_2_CLK] = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x1b8, 5); + clks[CLKGEN_CLK_OUT_3_CLK] = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x1bc, 5); + clks[CLKGEN_CLK_OUT_4_CLK] = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x1c0, 5); + clks[CLKGEN_NPUSYS_AXI_ACLK] = thead_clk_light_gate("clkgen_npusys_axi_aclk", "npu_cclk", ap_base + 0x1c8, 5); + clks[CLKGEN_SRAM_AXI_ACLK_0] = thead_clk_light_gate("clkgen_sram_axi_aclk_0", "npu_cclk", ap_base + 0x20c, 4); + clks[CLKGEN_APB_CPU2CFG_HCLK] = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cfg_apb_pclk", ap_base + 0x1c4, 5); + clks[CLKGEN_SRAM_AXI_ACLK_1] = thead_clk_light_gate("clkgen_sram_axi_aclk_1", "visys_aclk_m", ap_base + 0x20c, 3); + clks[CLKGEN_SRAM_AXI_ACLK_3] = thead_clk_light_gate("clkgen_sram_axi_aclk_3", "vpsys_axi_aclk", ap_base + 0x20c, 1); + clks[CLKGEN_VPSYS_VENC_CCLK] = thead_clk_light_gate("clkgen_vpsys_venc_cclk", "venc_cclk", ap_base + 0x1e4, 5); + clks[CLKGEN_EMMC_SDIO_REF_CLK] = thead_clk_light_gate("clkgen_emmc_sdio_ref_clk", "emmc_sdio_ref_clk", ap_base + 0x204, 30); + + clks[CLKGEN_X2H_CPUSYS_MHCLK] = thead_clk_light_gate_shared("clkgen_x2h_cpusys_mhclk", "ahb2_cpusys_hclk", ap_base + 0x120, 7, &share_cnt_x2h_cpusys_clk_en); + clks[CLKGEN_X2H_CPUSYS_ACLK] = thead_clk_light_gate_shared("clkgen_x2h_cpusys_aclk", "cfg_axi_aclk", ap_base + 0x120, 7, &share_cnt_x2h_cpusys_clk_en); + clks[CLKGEN_DMAC_CPUSYS_HCLK] = thead_clk_light_gate_shared("clkgen_dmac_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); + clks[CLKGEN_IOPMP_DMAC_CPUSYS_PCLK] = thead_clk_light_gate_shared("clkgen_iopmp_dmac_cpusys_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); + clks[CLKGEN_DMAC_CPUSYS_ACLK] = thead_clk_light_gate_shared("clkgen_dmac_cpusys_aclk", "axi4_cpusys2_aclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); + clks[CLKGEN_TIMER0_PCLK] = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); + clks[CLKGEN_TIMER0_CCLK] = thead_clk_light_gate_shared("clkgen_timer0_cclk", "timer_cclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); + clks[CLKGEN_TIMER1_PCLK] = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); + clks[CLKGEN_TIMER1_CCLK] = thead_clk_light_gate_shared("clkgen_timer1_cclk", "timer_cclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); + clks[CLKGEN_AXI4_CPUSYS2_PCLK] = thead_clk_light_gate_shared("clkgen_axi4_cpusys2_pclk", "apb3_cpusys_pclk", ap_base + 0x134, 5, &share_cnt_axi4_cpusys2_clk_en); + clks[CLKGEN_AXI4_CPUSYS2_ACLK] = thead_clk_light_gate_shared("clkgen_axi4_cpusys2_aclk", "axi4_cpusys2_aclk", ap_base + 0x134, 5, &share_cnt_axi4_cpusys2_clk_en); + clks[CLKGEN_BMU_C910_PCLK] = thead_clk_light_gate_shared("clkgen_bmu_c910_pclk", "apb3_cpusys_pclk", ap_base + 0x100, 5, &share_cnt_bmu_c910_clk_en); + clks[CLKGEN_BMU_C910_ACLK] = thead_clk_light_gate_shared("clkgen_bmu_c910_aclk", "axi4_cpusys1_aclk", ap_base + 0x100, 5, &share_cnt_bmu_c910_clk_en); + clks[CLKGEN_IOPMP_AON_PCLK] = thead_clk_light_gate_shared("clkgen_iopmp_aon_pclk", "apb3_cpusys_pclk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); + clks[CLKGEN_AON2CPU_A2X_ACLK] = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_aclk", "axi4_cpusys2_aclk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); + clks[CLKGEN_AON2CPU_A2X_HCLK] = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_hclk", "aonsys_bus_clk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); + clks[CLKGEN_IOPMP_CHIP_DBG_PCLK] = thead_clk_light_gate_shared("clkgen_iopmp_chip_dbg_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); + clks[CLKGEN_CHIP_DBG_ACLK] = thead_clk_light_gate_shared("clkgen_chip_dbg_aclk", "axi4_cpusys2_aclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); + clks[CLKGEN_CHIP_DBG_CCLK] = thead_clk_light_gate_shared("clkgen_chip_dbg_cclk", "chip_dbg_cclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); + clks[CLKGEN_X2X_CPUSYS_ACLK_M] = thead_clk_light_gate_shared("clkgen_x2x_cpusys_aclk_m", "axi4_cpusys2_aclk", ap_base + 0x134, 7, &share_cnt_x2x_cpusys_clk_en); + clks[CLKGEN_X2X_CPUSYS_ACLK_S] = thead_clk_light_gate_shared("clkgen_x2x_cpusys_aclk_s", "axi4_cpusys1_aclk", ap_base + 0x134, 7, &share_cnt_x2x_cpusys_clk_en); + clks[CLKGEN_CPU2PERI_X2H_ACLK] = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_aclk", "axi4_cpusys1_aclk", ap_base + 0x140, 9, &share_cnt_cpu2peri_x2h_clk_en); + clks[CLKGEN_CPU2PERI_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_mhclk", "perisys_ahb_hclk", ap_base + 0x140, 9, &share_cnt_cpu2peri_x2h_clk_en); + clks[CLKGEN_CPU2VI_X2H_ACLK] = thead_clk_light_gate_shared("clkgen_cpu2vi_x2h_aclk", "axi4_cpusys1_aclk", ap_base + 0x1d0, 21, &share_cnt_cpu2vi_x2h_clk_en); + clks[CLKGEN_CPU2VI_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cpu2vi_x2h_mhclk", "visys_ahb_hclk", ap_base + 0x1d0, 21, &share_cnt_cpu2vi_x2h_clk_en); + clks[CLKGEN_CFG2TEE_X2H_ACLK] = thead_clk_light_gate_shared("clkgen_cfg2tee_x2h_aclk", "cfg_axi_aclk", ap_base + 0x1cc, 24, &share_cnt_cfg2tee_x2h_clk_en); // just for teesys!!! + clks[CLKGEN_CFG2TEE_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cfg2tee_x2h_mhclk", "teesys_hclk", ap_base + 0x1cc, 24, &share_cnt_cfg2tee_x2h_clk_en); // just for teesys!!! + clks[CLKGEN_CPU2AON_X2H_ACLK] = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_aclk", "cfg_axi_aclk", ap_base + 0x138, 8, &share_cnt_cpu2aon_x2h_clk_en); + clks[CLKGEN_CPU2AON_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_mhclk", "aonsys_bus_clk", ap_base + 0x138, 8, &share_cnt_cpu2aon_x2h_clk_en); + clks[CLKGEN_CPU2VP_X2P_ACLK] = thead_clk_light_gate_shared("clkgen_cpu2vp_x2p_aclk", "cfg_axi_aclk", ap_base + 0x1e0, 13, &share_cnt_cpu2vp_x2p_clk_en); + clks[CLKGEN_CPU2VP_X2P_PCLK] = thead_clk_light_gate_shared("clkgen_cpu2vp_x2p_pclk", "vpsys_apb_pclk", ap_base + 0x1e0, 13, &share_cnt_cpu2vp_x2p_clk_en); + clks[CLKGEN_TOP_AXI4S_ACLK] = thead_clk_light_gate_shared("clkgen_top_axi4s_aclk", "cfg_axi_aclk", ap_base + 0x1c8, 4, &share_cnt_npu_core_clk_en); + clks[CLKGEN_TOP_APB_SX_PCLK] = thead_clk_light_gate_shared("clkgen_top_apb_sx_pclk", "cfg_apb_pclk", ap_base + 0x1c8, 4, &share_cnt_npu_core_clk_en); + clks[CLKGEN_MISC2VP_X2X_ACLK_M] = thead_clk_light_gate_shared("clkgen_misc2vp_x2x_aclk_m", "perisys_ahb_hclk", ap_base + 0x1e0, 15, &share_cnt_vpsys_axi_aclk_en); + clks[CLKGEN_VPSYS_ACLK] = thead_clk_light_gate_shared("clkgen_vpsys_aclk", "vpsys_axi_aclk", ap_base + 0x1e0, 15, &share_cnt_vpsys_axi_aclk_en); + clks[CLKGEN_GMAC1_HCLK] = thead_clk_light_gate_shared("clkgen_gmac1_hclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); + clks[CLKGEN_GMAC1_PCLK] = thead_clk_light_gate_shared("clkgen_gmac1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); + clks[CLKGEN_GMAC1_CCLK] = thead_clk_light_gate_shared("clkgen_gmac1_cclk", "gmac_cclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); + clks[CLKGEN_GMAC0_HCLK] = thead_clk_light_gate_shared("clkgen_gmac0_hclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); + clks[CLKGEN_GMAC0_PCLK] = thead_clk_light_gate_shared("clkgen_gmac0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); + clks[CLKGEN_GMAC0_CCLK] = thead_clk_light_gate_shared("clkgen_gmac0_cclk", "gmac_cclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); + clks[CLKGEN_PERI2PERI1_APB_HCLK] = thead_clk_light_gate_shared("clkgen_peri2peri1_apb_hclk", "perisys_ahb_hclk", ap_base + 0x150, 11, &share_cnt_perisys_apb3_hclk_en); + clks[CLKGEN_PERI2PERI1_APB_PCLK] = thead_clk_light_gate_shared("clkgen_peri2peri1_apb_pclk", "peri2sys_apb_pclk", ap_base + 0x150, 11, &share_cnt_perisys_apb3_hclk_en); + clks[CLKGEN_QSPI0_PCLK] = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); + clks[CLKGEN_QSPI0_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "qspi0_ssi_clk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); + clks[CLKGEN_GMAC_AXI_ACLK] = thead_clk_light_gate_shared("clkgen_gmac_axi_aclk", "perisys_ahb_hclk", ap_base + 0x204, 21, &share_cnt_gmac_axi_clk_en); + clks[CLKGEN_GMAC_AXI_PCLK] = thead_clk_light_gate_shared("clkgen_gmac_axi_pclk", "perisys_ahb_hclk", ap_base + 0x204, 21, &share_cnt_gmac_axi_clk_en); + clks[CLKGEN_GPIO0_PCLK] = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); + clks[CLKGEN_GPIO0_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio0_dbclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); + clks[CLKGEN_GPIO1_PCLK] = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 7, &share_cnt_gpio0_clk_en); + clks[CLKGEN_GPIO1_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio1_dbclk", ap_base + 0x204, 7, &share_cnt_gpio1_clk_en); + clks[CLKGEN_PWM_PCLK] = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_apb_pclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); + clks[CLKGEN_PWM_CCLK] = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); + clks[CLKGEN_SPI_PCLK] = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); + clks[CLKGEN_SPI_SSI_CLK] = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_ssi_clk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); + clks[CLKGEN_UART0_PCLK] = thead_clk_light_gate_shared("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); + clks[CLKGEN_UART0_SCLK] = thead_clk_light_gate_shared("clkgen_uart0_sclk", "uart_sclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); + clks[CLKGEN_UART2_PCLK] = thead_clk_light_gate_shared("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); + clks[CLKGEN_UART2_SCLK] = thead_clk_light_gate_shared("clkgen_uart2_sclk", "uart_sclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); + clks[CLKGEN_I2C2_PCLK] = thead_clk_light_gate_shared("clkgen_i2c2_pclk", "perisys_apb_pclk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2C2_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c2_ic_clk", "i2c_ic_clk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2C3_PCLK] = thead_clk_light_gate_shared("clkgen_i2c3_pclk", "perisys_apb_pclk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2C3_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c3_ic_clk", "i2c_ic_clk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2S_PCLK] = thead_clk_light_gate_shared("clkgen_i2s_pclk", "perisys_apb_pclk", ap_base + 0x1f0, 1, &share_cnt_peri_i2s_clk_en); + clks[CLKGEN_I2S_SRC_CLK] = thead_clk_light_gate_shared("clkgen_i2s_src_clk", "peri_i2s_src_clk", ap_base + 0x1f0, 1, &share_cnt_peri_i2s_clk_en); + clks[CLKGEN_QSPI1_PCLK] = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); + clks[CLKGEN_QSPI1_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "qspi1_ssi_clk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); + clks[CLKGEN_UART1_PCLK] = thead_clk_light_gate_shared("clkgen_uart1_pclk", "per2sys_apb_pclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); + clks[CLKGEN_UART1_SCLK] = thead_clk_light_gate_shared("clkgen_uart1_sclk", "uart_sclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); + clks[CLKGEN_UART3_PCLK] = thead_clk_light_gate_shared("clkgen_uart3_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); + clks[CLKGEN_UART3_SCLK] = thead_clk_light_gate_shared("clkgen_uart3_sclk", "uart_sclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); + clks[CLKGEN_UART4_PCLK] = thead_clk_light_gate_shared("clkgen_uart4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); + clks[CLKGEN_UART4_SCLK] = thead_clk_light_gate_shared("clkgen_uart4_sclk", "uart_sclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); + clks[CLKGEN_UART5_PCLK] = thead_clk_light_gate_shared("clkgen_uart5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); + clks[CLKGEN_UART5_SCLK] = thead_clk_light_gate_shared("clkgen_uart5_sclk", "uart_sclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); + clks[CLKGEN_I2C0_PCLK] = thead_clk_light_gate_shared("clkgen_i2c0_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); + clks[CLKGEN_I2C0_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c0_ic_clk", "i2c_ic_clk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); + clks[CLKGEN_I2C1_PCLK] = thead_clk_light_gate_shared("clkgen_i2c1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); + clks[CLKGEN_I2C1_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c1_ic_clk", "i2c_ic_clk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); + clks[CLKGEN_I2C4_PCLK] = thead_clk_light_gate_shared("clkgen_i2c4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); + clks[CLKGEN_I2C4_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c4_ic_clk", "i2c_ic_clk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); + clks[CLKGEN_I2C5_PCLK] = thead_clk_light_gate_shared("clkgen_i2c5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); + clks[CLKGEN_I2C5_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c5_ic_clk", "i2c_ic_clk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); + clks[CLKGEN_GPIO2_PCLK] = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); + clks[CLKGEN_GPIO2_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio2_dbclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); + clks[CLKGEN_GPIO3_PCLK] = thead_clk_light_gate_shared("clkgen_gpio3_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); //!!! gpio3 pclk is controlled by gpio2_clk_en + clks[CLKGEN_GPIO3_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio3_dbclk", "gpio3_dbclk", ap_base + 0x204, 20, &share_cnt_gpio3_clk_en); + clks[CLKGEN_VOSYS_AXI_ACLK] = thead_clk_light_gate_shared("clkgen_vosys_axi_aclk", "vosys_aclk_m", ap_base + 0x1dc, 5, &share_cnt_vosys_axi_aclk_en); + clks[CLKGEN_VOSYS_X2X_ACLK_S] = thead_clk_light_gate_shared("clkgen_vosys_x2x_aclk_s", "npu_cclk", ap_base + 0x1dc, 5, &share_cnt_vosys_axi_aclk_en); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + if (ret < 0) { + dev_err(dev, "failed to register clks for light\n"); + goto unregister_clks; + } + +#ifndef FPGA_EMU + /* HW defalut */ + clk_set_parent(clks[C910_CCLK], clks[CPU_PLL1_FOUTPOSTDIV]); +#else + clk_set_parent(clks[C910_CCLK_I0], clks[OSC_24M]); + clk_set_parent(clks[C910_CCLK], clks[C910_CCLK_I0]); +#endif + dev_info(dev, "succeed to register light fullmask clock driver\n"); + + return 0; + +unregister_clks: + thead_unregister_clocks(clks, ARRAY_SIZE(clks)); + return ret; +} + + +const bool tee_sys_flag; + +static const struct of_device_id light_clk_of_match[] = { + { .compatible = "thead,light-fm-ree-clk" }, + { .compatible = "thead,light-fm-tee-clk", .data = &tee_sys_flag,}, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, light_clk_of_match); + +static struct platform_driver light_clk_driver = { + .probe = light_clocks_probe, + .driver = { + .name = "light-fm-clk", + .of_match_table = of_match_ptr(light_clk_of_match), + }, +}; + +module_platform_driver(light_clk_driver); +MODULE_AUTHOR("wei.liu "); +MODULE_DESCRIPTION("Thead Light Fullmask clock driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/thead/clk-light-mpw.c b/drivers/clk/thead/clk-light-mpw.c new file mode 100644 index 00000000000000..f7356ddf4684eb --- /dev/null +++ b/drivers/clk/thead/clk-light-mpw.c @@ -0,0 +1,492 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static struct clk *clks[LIGHT_CLK_END]; +static struct clk_onecell_data clk_data; + +static u32 share_cnt_cpu2cfg_x2x_clk_en; +static u32 share_cnt_cpu2peri_x2h_clk_en; +static u32 share_cnt_aon2cpu_a2x_clk_en; +static u32 share_cnt_dmac_clk_en; +static u32 share_cnt_x2h_cpusys_clk_en; +static u32 share_cnt_cpu2tee_x2h_clk_en; +static u32 share_cnt_cpu2aon_x2h_clk_en; +static u32 share_cnt_cpu2cfg_x2h_clk_en; +static u32 share_cnt_timer0_clk_en; +static u32 share_cnt_timer1_clk_en; +static u32 share_cnt_peri2ddr_x2x_clk_en; +static u32 share_cnt_usb3_drd_clk_en; +static u32 share_cnt_gmac_clk_en; +static u32 share_cnt_emmc0_clk_en; +static u32 share_cnt_emmc1_clk_en; +static u32 share_cnt_pwm_clk_en; +static u32 share_cnt_qspi0_clk_en; +static u32 share_cnt_qspi1_clk_en; +static u32 share_cnt_spi_clk_en; +static u32 share_cnt_gpio0_clk_en; +static u32 share_cnt_gpio1_clk_en; +static u32 share_cnt_gpio2_clk_en; +static u32 share_cnt_dmac_1_clk_en; +static u32 share_cnt_dmac_2_clk_en; +static u32 share_cnt_dmac_3_clk_en; + +#ifdef THEAD_LIGHT_AON_CLK +static const char * const audio_pll_bypass_sels[] = {"audio_pll_foutpostdiv", "osc_24m", }; +static const char * const sys_pll_bypass_sels[] = {"sys_pll_foutpostdiv", "osc_24m", }; +#endif +#ifdef THEAD_LIGHT_DDR_CLK +static const char * const ddr_pll_bypass_sels[] = {"ddr_pll_foutpostdiv", "osc_24m", }; +#endif +static const char * const cpu_pll0_bypass_sels[] = {"cpu_pll0_foutpostdiv", "osc_24m", }; +static const char * const cpu_pll1_bypass_sels[] = {"cpu_pll1_foutpostdiv", "osc_24m", }; +static const char * const gmac_pll_bypass_sels[] = {"gmac_pll_foutpostdiv", "osc_24m", }; +static const char * const video_pll_bypass_sels[] = {"video_pll_foutpostdiv", "osc_24m", }; + +#ifdef THEAD_LIGHT_AON_CLK +static const char * const aonsys_clk_switch_0_sels[] = {"audio_pll_fout3", "osc_24m", }; +static const char * const aonsys_clk_switch_1_sels[] = {"aonsys_clk_switch_0", "rc_24m", }; +#endif + +static const char * const c910_cclk_i0_sels[] = {"cpu_pll0_bypass", "osc_24m", }; +static const char * const c910_cclk_sels[] = {"c910_cclk_i0", "cpu_pll1_foutpostdiv", }; +static const char * const cpusys_ahb_hclk_sel[] = {"cpusys_ahb_hclk_div", "osc_24m"}; +static const char * const cpusys_cfg_axi_aclk_sel[] = {"cpusys_cfg_axi_aclk_div", "osc_24m"}; +static const char * const perisys_ahb_hclk_sel[] = {"perisys_ahb_hclk_div", "osc_24m"}; +static const char * const clk_out_1_sel[] = {"clk_out_1_div", "osc_24m"}; +static const char * const clk_out_2_sel[] = {"clk_out_2_div", "osc_24m"}; +static const char * const clk_out_3_sel[] = {"clk_out_3_div", "osc_24m"}; +static const char * const clk_out_4_sel[] = {"clk_out_4_div", "osc_24m"}; + +static const struct light_pll_rate_table light_audiopll_tbl[] = { + LIGHT_PLL_RATE(2654208000U, 147456000U, 1, 110, 9932112, 6, 3), + LIGHT_PLL_RATE(884736000U, 294912000U, 1, 36, 14495600, 3, 1), +}; + +static const struct light_pll_rate_table light_syspll_tbl[] = { + LIGHT_PLL_RATE(2438553600U, 812851200U, 1, 101, 10173704, 3, 1), + LIGHT_PLL_RATE(884736000U, 294912000U, 1, 36, 14495600, 3, 1), +}; + +static const struct light_pll_rate_table light_cpupll_tbl[] = { + LIGHT_PLL_RATE(1800000000U, 1800000000U, 1, 75, 0, 1, 1), + LIGHT_PLL_RATE(3000000000U, 1500000000U, 1, 125, 0, 2, 1), + LIGHT_PLL_RATE(3000000000U, 1000000000U, 1, 125, 0, 3, 1), + LIGHT_PLL_RATE(3000000000U, 125000000U, 1, 125, 0, 6, 4), +}; + +#ifdef THEAD_LIGHT_DDR_CLK +static const struct light_pll_rate_table light_ddrpll_tbl[] = { + LIGHT_PLL_RATE(3192000000U, 798000000U, 1, 133, 0, 4, 1), + LIGHT_PLL_RATE(3192000000U, 532000000U, 1, 133, 0, 6, 1), + LIGHT_PLL_RATE(2112000000U, 1056000000U, 1, 88, 0, 2, 1), +}; +#endif + +#ifdef THEAD_LIGHT_AON_CLK +static struct light_pll_clk light_audio_pllvco = { + .out_type = LIGHT_PLL_VCO, + .clk_type = LIGHT_AUDIO_PLL, + .rate_table = light_audiopll_tbl, + .rate_count = ARRAY_SIZE(light_audiopll_tbl), +}; + +static struct light_pll_clk light_audio_plldiv = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_AUDIO_PLL, + .rate_table = light_audiopll_tbl, + .rate_count = ARRAY_SIZE(light_audiopll_tbl), +}; + +static struct light_pll_clk light_sys_pllvco = { + .out_type = LIGHT_PLL_VCO, + .clk_type = LIGHT_SYS_PLL, + .rate_table = light_syspll_tbl, + .rate_count = ARRAY_SIZE(light_syspll_tbl), +}; + +static struct light_pll_clk light_sys_plldiv = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_SYS_PLL, + .rate_table = light_syspll_tbl, + .rate_count = ARRAY_SIZE(light_syspll_tbl), +}; +#endif + +static struct light_pll_clk light_cpu_pll0vco = { + .out_type = LIGHT_PLL_VCO, + .clk_type = LIGHT_CPU_PLL0, + .rate_table = light_cpupll_tbl, + .rate_count = ARRAY_SIZE(light_cpupll_tbl), +}; + +static struct light_pll_clk light_cpu_pll0div = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_CPU_PLL0, + .rate_table = light_cpupll_tbl, + .rate_count = ARRAY_SIZE(light_cpupll_tbl), +}; + +static struct light_pll_clk light_cpu_pll1vco = { + .out_type = LIGHT_PLL_VCO, + .clk_type = LIGHT_CPU_PLL1, + .rate_table = light_cpupll_tbl, + .rate_count = ARRAY_SIZE(light_cpupll_tbl), +}; + +static struct light_pll_clk light_cpu_pll1div = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_CPU_PLL1, + .rate_table = light_cpupll_tbl, + .rate_count = ARRAY_SIZE(light_cpupll_tbl), +}; + +#ifdef THEAD_LIGHT_DDR_CLK +static struct light_pll_clk light_ddr_pllvco = { + .out_type = LIGHT_PLL_VCO, + .clk_type = LIGHT_DDR_PLL, + .rate_table = light_ddrpll_tbl, + .rate_count = ARRAY_SIZE(light_ddrpll_tbl), +}; + +static struct light_pll_clk light_ddr_plldiv = { + .out_type = LIGHT_PLL_DIV, + .clk_type = LIGHT_DDR_PLL, + .rate_table = light_ddrpll_tbl, + .rate_count = ARRAY_SIZE(light_ddrpll_tbl), +}; +#endif + +static int light_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *ap_base; +#ifdef THEAD_LIGHT_DDR_CLK + void __iomem *ddr_base; +#endif +#ifdef THEAD_LIGHT_AON_CLK + void __iomem *aon_base; +#endif + int ret; + +#ifdef THEAD_LIGHT_AON_CLK + np = of_find_compatible_node(NULL, NULL, "thead,light-aon-clk"); + aon_base = of_iomap(np, 0); + if (WARN_ON(!aon_base)) { + ret = -ENOMEM; + goto unregister_clks; + } + of_node_put(np); +#endif + + /* Clock source */ + clks[LIGHT_CLK_DUMMY] = thead_clk_fixed("dummy", 0); + clks[LIGHT_CLK_32K] = of_clk_get_by_name(np, "osc_32k"); + clks[LIGHT_CLK_24M] = of_clk_get_by_name(np, "osc_24m"); + clks[LIGHT_RC_24M] = of_clk_get_by_name(np, "rc_24m"); + + /* AP Fixed PLL */ + clks[LIGHT_VIDEO_PLL_FOUTVCO] = thead_clk_fixed("video_pll_foutvco", 2376000000); + clks[LIGHT_VIDEO_PLL_FOUTPOSTDIV] = thead_clk_fixed("video_pll_foutpostdiv", 796000000); + clks[LIGHT_GMAC_PLL_FOUTVCO] = thead_clk_fixed("gmac_pll_foutvco", 2000000000); + clks[LIGHT_GMAC_PLL_FOUTPOSTDIV] = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); + +#ifdef THEAD_LIGHT_AON_CLK + /* Aon PLL clocks */ + clks[LIGHT_AUDIO_PLL_FOUTVCO] = thead_light_pll("audio_pll_foutvco", "osc_24m", aon_base, &light_audio_pllvco); + clks[LIGHT_AUDIO_PLL_FOUTPOSTDIV] = thead_light_pll("audio_pll_foutpostdiv", "osc_24m", aon_base, &light_audio_plldiv); + clks[LIGHT_SYS_PLL_FOUTVCO] = thead_light_pll("sys_pll_foutvco", "osc_24m", aon_base, &light_sys_pllvco); + clks[LIGHT_SYS_PLL_FOUTPOSTDIV] = thead_light_pll("sys_pll_foutpostdiv", "osc_24m", aon_base, &light_sys_plldiv); +#endif + +#ifdef THEAD_LIGHT_DDR_CLK + np = of_find_compatible_node(NULL, NULL, "thead,light-ddr-clk"); + ddr_base = of_iomap(np, 0); + if (WARN_ON(!ddr_base)) { + ret = -ENOMEM; + goto unregister_clks; + } + of_node_put(np); + + /* DDR PLL */ + clks[LIGHT_DDR_PLL_FOUTVCO] = thead_light_pll("ddr_pll_foutvco", "osc_24m", ddr_base, &light_ddr_pllvco); + clks[LIGHT_DDR_PLL_FOUTPOSTDIV] = thead_light_pll("ddr_pll_foutpostdiv", "osc_24m", ddr_base, &light_ddr_plldiv); +#endif + + np = dev->of_node; + ap_base = devm_platform_ioremap_resource(pdev, 0); + if (WARN_ON(IS_ERR(ap_base))) { + ret = PTR_ERR(ap_base); + goto unregister_clks; + } + + /* AP PLL clocks */ + clks[LIGHT_CPU_PLL0_FOUTVCO] = thead_light_pll("cpu_pll0_foutvco", "osc_24m", ap_base, &light_cpu_pll0vco); + clks[LIGHT_CPU_PLL0_FOUTPOSTDIV] = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); + clks[LIGHT_CPU_PLL1_FOUTVCO] = thead_light_pll("cpu_pll1_foutvco", "osc_24m", ap_base, &light_cpu_pll1vco); + clks[LIGHT_CPU_PLL1_FOUTPOSTDIV] = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); + + /* PLL bypass */ +#ifdef THEAD_LIGHT_AON_CLK + clks[LIGHT_AUDIO_PLL_BYPASS] = thead_light_clk_mux_flags("audio_pll_bypass", aon_base + 0x4, 31, 1, audio_pll_bypass_sels, ARRAY_SIZE(audio_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[LIGHT_SYS_PLL_BYPASS] = thead_light_clk_mux_flags("sys_pll_bypass", aon_base + 0x14, 31, 1, sys_pll_bypass_sels, ARRAY_SIZE(sys_pll_bypass_sels), CLK_SET_RATE_PARENT); +#endif +#ifdef THEAD_LIGHT_DDR_CLK + clks[LIGHT_DDR_PLL_BYPASS] = thead_light_clk_mux_flags("ddr_pll_bypass", ddr_base + 0xc, 31, 1, ddr_pll_bypass_sels, ARRAY_SIZE(ddr_pll_bypass_sels), CLK_SET_RATE_PARENT); +#endif + clks[LIGHT_CPU_PLL0_BYPASS] = thead_light_clk_mux_flags("cpu_pll0_bypass", ap_base + 0x4, 31, 1, cpu_pll0_bypass_sels, ARRAY_SIZE(cpu_pll0_bypass_sels), CLK_SET_RATE_PARENT); + clks[LIGHT_CPU_PLL1_BYPASS] = thead_light_clk_mux_flags("cpu_pll1_bypass", ap_base + 0x14, 31, 1, cpu_pll1_bypass_sels, ARRAY_SIZE(cpu_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[LIGHT_GMAC_PLL_BYPASS] = thead_light_clk_mux_flags("gmac_pll_bypass", ap_base + 0x24, 31, 1, gmac_pll_bypass_sels, ARRAY_SIZE(gmac_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[LIGHT_VIDEO_PLL_BYPASS] = thead_light_clk_mux_flags("video_pll_bypass", ap_base + 0x34, 31, 1, video_pll_bypass_sels, ARRAY_SIZE(video_pll_bypass_sels), CLK_SET_RATE_PARENT); + + /* PLL FOUT */ +#ifdef THEAD_LIGHT_AON_CLK + clks[LIGHT_AUDIO_PLL_FOUT3] = thead_light_clk_fixed_factor("audio_pll_fout3", "audio_pll_bypass", 1, 6); + clks[LIGHT_SYS_PLL_FOUT4] = thead_light_clk_fixed_factor("sys_pll_fout4", "sys_pll_bypass", 1, 8); +#endif +#ifdef THEAD_LIGHT_DDR_CLK + clks[LIGHT_DDR_PLL_FOUT4] = thead_light_clk_fixed_factor("ddr_pll_fout4", "ddr_pll_bypass", 1, 8); +#endif + clks[LIGHT_CPU_PLL0_FOUT4] = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); + clks[LIGHT_CPU_PLL1_FOUT4] = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); + clks[LIGHT_GMAC_PLL_FOUT1PH0] = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); + clks[LIGHT_GMAC_CORECLK] = thead_light_clk_fixed_factor("gmac_coreclk", "gmac_pll_fout1ph0", 1, 1); + clks[LIGHT_GMAC_PLL_FOUT4] = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); + clks[LIGHT_VIDEO_PLL_FOUT4] = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); + clks[LIGHT_GMAC_PLL_FOUTVCO_DIV5] = thead_light_clk_fixed_factor("gmac_pll_foutvco_div5", "gmac_pll_foutvco", 1, 5); + clks[LIGHT_OSC_CLK_DIV24] = thead_light_clk_fixed_factor("osc_clk_div24", "osc_24m", 1, 24); + clks[LIGHT_CHIP_DBG_CCLK] = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); + clks[LIGHT_AXI_ACLK] = thead_light_clk_fixed_factor("cpusys_axi_aclk", "cpu_pll0_bypass", 1, 2); + clks[LIGHT_X2H_HCLK] = thead_light_clk_fixed_factor("aonsys_x2h_hclk", "osc_24m", 1, 1); + clks[LIGHT_EMMC_CLK_DIV] = thead_light_clk_fixed_factor("emmc_clk_div", "video_pll_bypass", 1, 4); + clks[LIGHT_EMMC0_OSC_CLK] = thead_light_clk_fixed_factor("emmc0_osc_clk", "osc_24m", 1, 1); + clks[LIGHT_EMMC1_OSC_CLK] = thead_light_clk_fixed_factor("emmc1_osc_clk", "osc_24m", 1, 1); + clks[LIGHT_PWM_CCLK] = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); + clks[LIGHT_USB3_PHY_REF_CLK] = thead_light_clk_fixed_factor("usb3_phy_ref_clk", "osc_24m", 1, 1); + clks[LIGHT_SPI_CLK] = thead_light_clk_fixed_factor("spi_clk", "gmac_pll_foutvco_div5", 1, 1); + clks[LIGHT_GPIO_DBCLK] = thead_light_clk_fixed_factor("gpio_dbclk", "osc_32k", 1, 1); + +#ifdef THEAD_LIGHT_AON_CLK + /* Aon sys mux tree */ + clks[LIGHT_AONSYS_CLK_SWITCH_0] = thead_light_clk_mux_flags("aonsys_clk_switch_0", aon_base + 0x100, 4, 1, aonsys_clk_switch_0_sels, ARRAY_SIZE(aonsys_clk_switch_0_sels), CLK_SET_RATE_PARENT); + clks[LIGHT_AONSYS_CLK_SWITCH_1] = thead_light_clk_mux_flags("aonsys_clk_switch_1", aon_base + 0x100, 5, 1, aonsys_clk_switch_1_sels, ARRAY_SIZE(aonsys_clk_switch_1_sels), CLK_SET_RATE_PARENT); + + /* Aon sys div tree */ + clks[LIGHT_AONSYS_CLK] = thead_clk_light_divider("aonsys_clk", "aonsys_clk_switch_1", aon_base + 0x100, 0, 3, 3, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_SHARE_SRAM_CLK] = thead_clk_light_divider("share_sram_clk", "sys_pll_foutvco", aon_base + 0x104, 0, 4, 4, MUX_TYPE_DIV, 3, 12); + + /* Aon sys gate tree */ + clks[LIGHT_CLKGEN_RTC_PCLK] = thead_clk_light_gate("rtc_pclk_en", "aonsys_clk", aon_base + 0x120, 0); + clks[LIGHT_CLKGEN_AOGPIO_PCLK] = thead_clk_light_gate("aogpio_pclk_en", "aonsys_clk", aon_base + 0x120, 1); + clks[LIGHT_CLKGEN_AOI2C_PCLK] = thead_clk_light_gate("aoi2c_pclk_en", "aonsys_clk", aon_base + 0x120, 2); + clks[LIGHT_CLKGEN_PVTC_PCLK] = thead_clk_light_gate("pvtc_pclk_en", "aonsys_clk", aon_base + 0x120, 3); + clks[LIGHT_CLKGEN_SRAM_AXI_ACLK] = thead_clk_light_gate("share_sram_clk_en", "aonsys_clk", aon_base + 0x120, 4); + clks[LIGHT_CLKGEN_AOPAD_PCLK] = thead_clk_light_gate("aopad_pclk_en", "aonsys_clk", aon_base + 0x120, 5); + clks[LIGHT_CLKGEN_AOAPB_HCLK] = thead_clk_light_gate("aoapb_hclk_en", "aonsys_clk", aon_base + 0x120, 6); + clks[LIGHT_CLKGEN_AOSRAM_HCLK] = thead_clk_light_gate("aosram_hclk_en", "aonsys_clk", aon_base + 0x120, 7); + clks[LIGHT_CLKGEN_AOAHB_HCLK] = thead_clk_light_gate("aoahb_hclk_en", "aonsys_clk", aon_base + 0x120, 8); + clks[LIGHT_CLKGEN_AOGPIO_DBCLK] = thead_clk_light_gate("aogpio_dbclk_en", "aonsys_clk", aon_base + 0x120, 9); + clks[LIGHT_CLKGEN_AOTIMER_PCLK] = thead_clk_light_gate("aotimer_pclk_en", "aonsys_clk", aon_base + 0x120, 10); + clks[LIGHT_CLKGEN_AOTIMER_CCLK] = thead_clk_light_gate("aotimer_cclk_en", "aonsys_clk", aon_base + 0x120, 11); + clks[LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S] = thead_clk_light_gate("apsys_clk_en", "aonsys_clk", aon_base + 0x130, 0); +#endif + + /* AP sys mux tree */ + clks[LIGHT_C910_CCLK_I0] = thead_light_clk_mux_flags("c910_cclk_i0", ap_base + 0x100, 1, 1, c910_cclk_i0_sels, ARRAY_SIZE(c910_cclk_i0_sels), CLK_SET_RATE_PARENT); + clks[LIGHT_C910_CCLK] = thead_light_clk_mux_flags("c910_cclk", ap_base + 0x100, 0, 1, c910_cclk_sels, ARRAY_SIZE(c910_cclk_sels), CLK_SET_RATE_PARENT); + clks[LIGHT_CPUSYS_AHB_HCLK] = thead_light_clk_mux_flags("cpusys_ahb_hclk", ap_base + 0x120, 5, 1, cpusys_ahb_hclk_sel, ARRAY_SIZE(cpusys_ahb_hclk_sel), CLK_SET_RATE_PARENT); + clks[LIGHT_CPUSYS_CFG_AXI_ACLK] = thead_light_clk_mux_flags("cpusys_cfg_axi_aclk", ap_base + 0x138, 5, 1, cpusys_cfg_axi_aclk_sel, ARRAY_SIZE(cpusys_cfg_axi_aclk_sel), CLK_SET_RATE_PARENT); + clks[LIGHT_PERISYS_AHB_HCLK] = thead_light_clk_mux_flags("perisys_ahb_hclk", ap_base + 0x40, 5, 1, perisys_ahb_hclk_sel, ARRAY_SIZE(perisys_ahb_hclk_sel), CLK_SET_RATE_PARENT); + clks[LIGHT_CLK_OUT_1] = thead_light_clk_mux_flags("clk_out_1", ap_base + 0x1b4, 4, 1, clk_out_1_sel, ARRAY_SIZE(clk_out_1_sel), CLK_SET_RATE_PARENT); + clks[LIGHT_CLK_OUT_2] = thead_light_clk_mux_flags("clk_out_2", ap_base + 0x1b8, 4, 1, clk_out_2_sel, ARRAY_SIZE(clk_out_2_sel), CLK_SET_RATE_PARENT); + clks[LIGHT_CLK_OUT_3] = thead_light_clk_mux_flags("clk_out_3", ap_base + 0x1bc, 4, 1, clk_out_3_sel, ARRAY_SIZE(clk_out_3_sel), CLK_SET_RATE_PARENT); + clks[LIGHT_CLK_OUT_4] = thead_light_clk_mux_flags("clk_out_4", ap_base + 0x1c0, 4, 1, clk_out_4_sel, ARRAY_SIZE(clk_out_4_sel), CLK_SET_RATE_PARENT); + + /* AP sys div tree */ + clks[LIGHT_CPUSYS_AHB_HCLK_DIV] = thead_clk_light_divider("cpusys_ahb_hclk_div", "gmac_pll_fout1ph0", ap_base + 0x120, 0, 4, 4, MUX_TYPE_DIV, 2, 8); + clks[LIGHT_APB3_CPUSYS_PCLK] = thead_clk_light_divider("apb3_cpusys_pclk", "cpusys_ahb_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); + clks[LIGHT_CPUSYS_SUB_AXI_ACLK] = thead_clk_light_divider("cpusys_sub_axi_aclk", "gmac_pll_bypass", ap_base + 0x134, 0, 4, 4, MUX_TYPE_DIV, 2, 8); + clks[LIGHT_CPUSYS_CFG_AXI_ACLK_DIV] = thead_clk_light_divider("cpusys_cfg_axi_aclk_div", "gmac_pll_bypass", ap_base + 0x138, 0, 4, 4, MUX_TYPE_DIV, 8, 15); + clks[LIGHT_TEESYS_HCLK] = thead_clk_light_divider("teesys_hclk", "gmac_pll_fout1ph0", ap_base + 0x154, 0, 2, 2, MUX_TYPE_DIV, 2, 3); + clks[LIGHT_DMAC_1_CLK] = thead_clk_light_divider("dmac_1_clk", "video_pll_bypass", ap_base + 0x158, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_DMAC_2_CLK] = thead_clk_light_divider("dmac_2_clk", "video_pll_bypass", ap_base + 0x16c, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_DMAC_3_CLK] = thead_clk_light_divider("dmac_3_clk", "gmac_pll_bypass", ap_base + 0x160, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_AXI_PORT4_CLK] = thead_clk_light_divider("axi_port4_clk", "video_pll_bypass", ap_base + 0x164, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_PERISYS_AHB_HCLK_DIV] = thead_clk_light_divider("perisys_ahb_hclk_div", "gmac_pll_fout1ph0", ap_base + 0x140, 0, 4, 4, MUX_TYPE_DIV, 2, 8); + clks[LIGHT_PERISYS_APB_PCLK] = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); + clks[LIGHT_CLK_OUT_1_DIV] = thead_clk_light_divider("clk_out_1_div", "osc_24m", ap_base + 0x1b4, 0, 3, 3, MUX_TYPE_DIV, 2, 7); + clks[LIGHT_CLK_OUT_2_DIV] = thead_clk_light_divider("clk_out_2_div", "osc_24m", ap_base + 0x1b8, 0, 3, 3, MUX_TYPE_DIV, 2, 7); + clks[LIGHT_CLK_OUT_3_DIV] = thead_clk_light_divider("clk_out_3_div", "osc_24m", ap_base + 0x1bc, 0, 3, 3, MUX_TYPE_DIV, 2, 7); + clks[LIGHT_CLK_OUT_4_DIV] = thead_clk_light_divider("clk_out_4_div", "osc_24m", ap_base + 0x1c0, 0, 3, 3, MUX_TYPE_DIV, 2, 7); + + /* AP sys gate tree */ + clks[LIGHT_CLKGEN_PERISYS_AXI_ACLK] = thead_clk_light_gate("clkgen_perisys_axi_aclk", "perisys_ahb_hclk", ap_base + 0x200, 31); + clks[LIGHT_CLKGEN_PERISYS_AHB_HCLK] = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x200, 30); + clks[LIGHT_CLKGEN_PERISYS_APB1_HCLK] = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 29); + clks[LIGHT_CLKGEN_PERISYS_APB2_HCLK] = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x200, 28); + clks[LIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK] = thead_clk_light_gate("clkgen_usb3_drd_phy_ref_clk", "usb3_phy_ref_clk", ap_base + 0x200, 27); + clks[LIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK] = thead_clk_light_gate("clkgen_usb3_drd_ctrl_ref_clk", "usb3_ctrl_ref_clk", ap_base + 0x200, 26); + clks[LIGHT_CLKGEN_USB3_DRD_SPDCLK] = thead_clk_light_gate("clkgen_usb3_drd_spdclk", "osc_clk_div24", ap_base + 0x200, 25); + clks[LIGHT_CLKGEN_EMMC1_X2X_ACLK] = thead_clk_light_gate("clkgen_emmc1_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 23); + clks[LIGHT_CLKGEN_EMMC0_X2X_ACLK] = thead_clk_light_gate("clkgen_emmc0_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 22); + clks[LIGHT_CLKGEN_UART0_PCLK] = thead_clk_light_gate("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x200, 14); + clks[LIGHT_CLKGEN_UART1_PCLK] = thead_clk_light_gate("clkgen_uart1_pclk", "perisys_apb_pclk", ap_base + 0x200, 13); + clks[LIGHT_CLKGEN_UART2_PCLK] = thead_clk_light_gate("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x200, 12); + clks[LIGHT_CLKGEN_UART3_PCLK] = thead_clk_light_gate("clkgen_uart3_pclk", "perisys_apb_pclk", ap_base + 0x200, 11); + clks[LIGHT_CLKGEN_UART4_PCLK] = thead_clk_light_gate("clkgen_uart4_pclk", "perisys_apb_pclk", ap_base + 0x200, 10); + clks[LIGHT_CLKGEN_UART5_PCLK] = thead_clk_light_gate("clkgen_uart5_pclk", "perisys_apb_pclk", ap_base + 0x200, 9); + clks[LIGHT_CLKGEN_I2C0_IC_CLK] = thead_clk_light_gate("clkgen_i2c0_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 5); + clks[LIGHT_CLKGEN_I2C1_IC_CLK] = thead_clk_light_gate("clkgen_i2c1_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 4); + clks[LIGHT_CLKGEN_I2C2_IC_CLK] = thead_clk_light_gate("clkgen_i2c2_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 3); + clks[LIGHT_CLKGEN_I2C3_IC_CLK] = thead_clk_light_gate("clkgen_i2c3_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 2); + clks[LIGHT_CLKGEN_I2C4_IC_CLK] = thead_clk_light_gate("clkgen_i2c4_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 1); + clks[LIGHT_CLKGEN_I2C5_IC_CLK] = thead_clk_light_gate("clkgen_i2c5_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 0); + + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_4_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 28); + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_3_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 27); + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_2_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 26); + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_1_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 25); + clks[LIGHT_CLKGEN_APB_CPU2FG_HCLK] = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 24); + clks[LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M] = thead_clk_light_gate("clkgen_cpu2ram_x2x_aclk_m", "cpusys_axi_aclk", ap_base + 0x204, 21); + clks[LIGHT_CLKGEN_AXI4_CPUSYS2_ACLK] = thead_clk_light_gate("clkgen_axi4_cpusys2_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 20); + clks[LIGHT_CLKGEN_X2X_CPUSYS_ACLK_M] = thead_clk_light_gate("clkgen_x2x_cpusys_aclk_m", "cpusys_sub_axi_aclk", ap_base + 0x204, 19); + clks[LIGHT_CLKGEN_CHIP_DBG_ACLK] = thead_clk_light_gate("clkgen_chip_dbg_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 18); + clks[LIGHT_CLKGEN_AXI4_CFG_BUS_ACLK] = thead_clk_light_gate("clkgen_axi4_cfg_bus_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 17); + clks[LIGHT_CLKGEN_AHB2_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 11); + clks[LIGHT_CLKGEN_APB3_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 10); + clks[LIGHT_CLKGEN_C910_BROM_HCLK] = thead_clk_light_gate("clkgen_c910_brom_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 9); + clks[LIGHT_CLKGEN_MBOX0_PCLK] = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 7); + clks[LIGHT_CLKGEN_MBOX1_PCLK] = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 6); + clks[LIGHT_CLKGEN_MBOX2_PCLK] = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 5); + clks[LIGHT_CLKGEN_MBOX3_PCLK] = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 4); + clks[LIGHT_CLKGEN_WDT0_PCLK] = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 3); + clks[LIGHT_CLKGEN_WDT1_PCLK] = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 2); + + clks[LIGHT_CLKGEN_TRNG_RB_HCLK] = thead_clk_light_gate("clkgen_trng_rb_hclk", "teesys_hclk", ap_base + 0x208, 19); + clks[LIGHT_CLKGEN_ADC_PCLK] = thead_clk_light_gate("clkgen_adc_pclk", "perisys_apb_pclk", ap_base + 0x208, 18); + clks[LIGHT_CLKGEN_AXI_ACLK_4] = thead_clk_light_gate("axi_aclk_4", "axi_port4_clk", ap_base + 0x208, 17); + clks[LIGHT_CLKGEN_AXI_ACLK_3] = thead_clk_light_gate("axi_aclk_3", "dmac_3_clk", ap_base + 0x208, 16); + clks[LIGHT_CLKGEN_AXI_ACLK_2] = thead_clk_light_gate("axi_aclk_2", "dmac_2_clk", ap_base + 0x208, 15); + clks[LIGHT_CLKGEN_AXI_ACLK_1] = thead_clk_light_gate("axi_aclk_1", "dmac_1_clk", ap_base + 0x208, 14); + clks[LIGHT_CLKGEN_AXI_ACLK_0] = thead_clk_light_gate("axi_aclk_0", "cpusys_axi_aclk", ap_base + 0x208, 13); + clks[LIGHT_CLKGEN_SRAM_AXI_PCLK] = thead_clk_light_gate("clkgen_sram_axi_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 9); + clks[LIGHT_CLKGEN_AHB2_TEESYS_HCLK] = thead_clk_light_gate("clkgen_ahb2_teesys_hclk", "teesys_hclk", ap_base + 0x208, 8); + clks[LIGHT_CLKGEN_EFUSE_MPW_PCLK] = thead_clk_light_gate("clkgen_efuse_mpw_pclk", "perisys_apb_pclk", ap_base + 0x208, 7); + clks[LIGHT_CLKGEN_CLK_OUT_4_CLK] = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x208, 6); + clks[LIGHT_CLKGEN_CLK_OUT_3_CLK] = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x208, 5); + clks[LIGHT_CLKGEN_CLK_OUT_2_CLK] = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x208, 4); + clks[LIGHT_CLKGEN_CLK_OUT_1_CLK] = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x208, 3); + clks[LIGHT_CLKGEN_DDR_APB_PCLK] = thead_clk_light_gate("clkgen_ddr_apb_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 2); + clks[LIGHT_CLKGEN_PADCTRL_APSYS_PCLK] = thead_clk_light_gate("clkgen_padctrl_apsys_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 1); + clks[LIGHT_CLKGEN_CHIP_DBG_CCLK] = thead_clk_light_gate("clkgen_chip_dbg_cclk", "chip_dbg_cclk", ap_base + 0x208, 0); + + /* register AP shared gate */ + clks[LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_M] = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2x_aclk_m", "cpusys_axi_aclk", ap_base + 0x204, 22, &share_cnt_cpu2cfg_x2x_clk_en); + clks[LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_S] = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2x_aclk_s", "cpusys_cfg_axi_aclk", ap_base + 0x204, 22, &share_cnt_cpu2cfg_x2x_clk_en); + clks[LIGHT_CLKGEN_CPU2PERI_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_mhclk", "perisys_ahb_hclk", ap_base + 0x204, 12, &share_cnt_cpu2peri_x2h_clk_en); + clks[LIGHT_CLKGEN_CPU2CFG_X2H_ACLK_S] = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_aclk", "cpusys_axi_aclk", ap_base + 0x204, 12, &share_cnt_cpu2peri_x2h_clk_en); + clks[LIGHT_CLKGEN_AON2CPU_A2X_ACLK] = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 23, &share_cnt_aon2cpu_a2x_clk_en); + clks[LIGHT_CLKGEN_AON2CPU_A2X_HCLK] = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_hclk", "aonsys_x2h_hclk", ap_base + 0x204, 23, &share_cnt_aon2cpu_a2x_clk_en); + clks[LIGHT_CLKGEN_DMAC_ACLK] = thead_clk_light_gate_shared("clkgen_dmac_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); + clks[LIGHT_CLKGEN_DMAC_HCLK] = thead_clk_light_gate_shared("clkgen_dmac_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); + clks[LIGHT_CLKGEN_X2H_CPUSYS_ACLK] = thead_clk_light_gate_shared("clkgen_x2h_cpusys_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 16, &share_cnt_x2h_cpusys_clk_en); + clks[LIGHT_CLKGEN_X2H_CPUSYS_MHCLK] = thead_clk_light_gate_shared("clkgen_x2h_cpusys_mhclk", "cpusys_ahb_hclk", ap_base + 0x204, 16, &share_cnt_x2h_cpusys_clk_en); + clks[LIGHT_CLKGEN_CPU2TEE_X2H_ACLK] = thead_clk_light_gate_shared("clkgen_cpu2tee_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 15, &share_cnt_cpu2tee_x2h_clk_en); + clks[LIGHT_CLKGEN_CPU2TEE_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cpu2tee_x2h_mhclk", "teesys_hclk", ap_base + 0x204, 15, &share_cnt_cpu2tee_x2h_clk_en); + clks[LIGHT_CLKGEN_CPU2AON_X2H_ACLK] = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 14, &share_cnt_cpu2aon_x2h_clk_en); + clks[LIGHT_CLKGEN_CPU2AON_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_mhclk", "aonsys_x2h_hclk", ap_base + 0x204, 14, &share_cnt_cpu2aon_x2h_clk_en); + clks[LIGHT_CLKGEN_CPU2CFG_X2H_ACLK] = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 13, &share_cnt_cpu2cfg_x2h_clk_en); + clks[LIGHT_CLKGEN_CPU2CFG_X2H_MHCLK] = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2h_mhclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 13, &share_cnt_cpu2cfg_x2h_clk_en); + clks[LIGHT_CLKGEN_TIMER0_CCLK] = thead_clk_light_gate_shared("clkgen_timer0_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); + clks[LIGHT_CLKGEN_TIMER0_PCLK] = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); + clks[LIGHT_CLKGEN_TIMER1_CCLK] = thead_clk_light_gate_shared("clkgen_timer1_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); + clks[LIGHT_CLKGEN_TIMER1_PCLK] = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); + clks[LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_M] = thead_clk_light_gate_shared("clkgen_peri2ddr_x2x_aclk_m", "perisys_ahb_hclk", ap_base + 0x204, 29, &share_cnt_peri2ddr_x2x_clk_en); + clks[LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_S] = thead_clk_light_gate_shared("clkgen_peri2ddr_x2x_aclk_s", "axi_port4_clk", ap_base + 0x204, 29, &share_cnt_peri2ddr_x2x_clk_en); + clks[LIGHT_CLKGEN_USB3_DRD_ACLK] = thead_clk_light_gate_shared("clkgen_usb3_drd_aclk", "perisys_ahb_hclk", ap_base + 0x200, 24, &share_cnt_usb3_drd_clk_en); + clks[LIGHT_CLKGEN_USB3_DRD_PCLK] = thead_clk_light_gate_shared("clkgen_usb3_drd_pclk", "perisys_apb_pclk", ap_base + 0x200, 24, &share_cnt_usb3_drd_clk_en); + clks[LIGHT_CLKGEN_GMAC_HCLK] = thead_clk_light_gate_shared("clkgen_gmac_hclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_GMAC_ACLK] = thead_clk_light_gate_shared("clkgen_gmac_aclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_GMAC_PCLK] = thead_clk_light_gate_shared("clkgen_gmac_pclk", "perisys_apb_pclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_GMAC_CCLK] = thead_clk_light_gate_shared("clkgen_gmac_cclk", "gmac_coreclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_EMMC0_HCLK] = thead_clk_light_gate_shared("clkgen_emmc0_hclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); + clks[LIGHT_CLKGEN_EMMC0_ACLK] = thead_clk_light_gate_shared("clkgen_emmc0_aclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); + clks[LIGHT_CLKGEN_EMMC0_REF_CLK] = thead_clk_light_gate_shared("clkgen_emmc0_ref_clk", "emmc_clk_div", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); + clks[LIGHT_CLKGEN_EMMC0_OSC_CLK] = thead_clk_light_gate_shared("clkgen_emmc0_osc_clk", "emmc0_osc_clk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); + clks[LIGHT_CLKGEN_EMMC1_HCLK] = thead_clk_light_gate_shared("clkgen_emmc1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); + clks[LIGHT_CLKGEN_EMMC1_ACLK] = thead_clk_light_gate_shared("clkgen_emmc1_aclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); + clks[LIGHT_CLKGEN_EMMC1_REF_CLK] = thead_clk_light_gate_shared("clkgen_emmc1_ref_clk", "emmc_clk_div", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); + clks[LIGHT_CLKGEN_EMMC1_OSC_CLK] = thead_clk_light_gate_shared("clkgen_emmc1_osc_clk", "emmc1_osc_clk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); + clks[LIGHT_CLKGEN_PWM_PCLK] = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_ahb_hclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); + clks[LIGHT_CLKGEN_PWM_CCLK] = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); + clks[LIGHT_CLKGEN_QSPI0_PCLK] = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_apb_pclk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); + clks[LIGHT_CLKGEN_QSPI0_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "spi_clk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); + clks[LIGHT_CLKGEN_QSPI1_PCLK] = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "perisys_apb_pclk", ap_base + 0x200, 16, &share_cnt_qspi1_clk_en); + clks[LIGHT_CLKGEN_QSPI1_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "spi_clk", ap_base + 0x200, 16, &share_cnt_qspi0_clk_en); + clks[LIGHT_CLKGEN_SPI_PCLK] = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); + clks[LIGHT_CLKGEN_SPI_SSI_CLK] = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_clk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); + clks[LIGHT_CLKGEN_GPIO0_PCLK] = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_apb_pclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); + clks[LIGHT_CLKGEN_GPIO0_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio_dbclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); + clks[LIGHT_CLKGEN_GPIO1_PCLK] = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_apb_pclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); + clks[LIGHT_CLKGEN_GPIO1_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio_dbclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); + clks[LIGHT_CLKGEN_GPIO2_PCLK] = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "perisys_apb_pclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); + clks[LIGHT_CLKGEN_GPIO2_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio_dbclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); + clks[LIGHT_CLKGEN_DMAC_1_ACLK] = thead_clk_light_gate_shared("clkgen_dmac_1_aclk", "dmac_1_clk", ap_base + 0x208, 12, &share_cnt_dmac_1_clk_en); + clks[LIGHT_CLKGEN_DMAC_1_HCLK] = thead_clk_light_gate_shared("clkgen_dmac_1_hclk", "teesys_hclk", ap_base + 0x208, 12, &share_cnt_dmac_1_clk_en); + clks[LIGHT_CLKGEN_DMAC_2_ACLK] = thead_clk_light_gate_shared("clkgen_dmac_2_aclk", "dmac_2_clk", ap_base + 0x208, 11, &share_cnt_dmac_2_clk_en); + clks[LIGHT_CLKGEN_DMAC_2_HCLK] = thead_clk_light_gate_shared("clkgen_dmac_2_hclk", "teesys_hclk", ap_base + 0x208, 11, &share_cnt_dmac_2_clk_en); + clks[LIGHT_CLKGEN_DMAC_3_ACLK] = thead_clk_light_gate_shared("clkgen_dmac_3_aclk", "dmac_3_clk", ap_base + 0x208, 10, &share_cnt_dmac_3_clk_en); + clks[LIGHT_CLKGEN_DMAC_3_HCLK] = thead_clk_light_gate_shared("clkgen_dmac_3_hclk", "teesys_hclk", ap_base + 0x208, 10, &share_cnt_dmac_3_clk_en); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + if (ret < 0) { + dev_err(dev, "failed to register clks for light\n"); + goto unregister_clks; + } + + /* HW defalut */ + clk_set_parent(clks[LIGHT_C910_CCLK], clks[LIGHT_CPU_PLL1_FOUTPOSTDIV]); + + return 0; + +unregister_clks: + thead_unregister_clocks(clks, ARRAY_SIZE(clks)); + return ret; +} + +static const struct of_device_id light_clk_of_match[] = { + { .compatible = "thead,light-mpw-clk" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, light_clk_of_match); + +static struct platform_driver light_clk_driver = { + .probe = light_clocks_probe, + .driver = { + .name = "light-mpw-clk", + .of_match_table = of_match_ptr(light_clk_of_match), + }, +}; + +module_platform_driver(light_clk_driver); +MODULE_AUTHOR("fugang.duan "); +MODULE_DESCRIPTION("Thead Light MPW clock driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/thead/clk.c b/drivers/clk/thead/clk.c new file mode 100644 index 00000000000000..2e181a9fd18027 --- /dev/null +++ b/drivers/clk/thead/clk.c @@ -0,0 +1,739 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define LIGHT_PLL_CFG0 0x0 +#define LIGHT_PLL_CFG1 0x04 +#define LIGHT_PLL_CFG2 0x8 +#define LIGHT_POSTDIV2_SHIFT 24 +#define LIGHT_POSTDIV2_MASK GENMASK(26, 24) +#define LIGHT_POSTDIV1_SHIFT 20 +#define LIGHT_POSTDIV1_MASK GENMASK(22, 20) +#define LIGHT_FBDIV_SHIFT 8 +#define LIGHT_FBDIV_MASK GENMASK(19, 8) +#define LIGHT_REFDIV_SHIFT 0 +#define LIGHT_REFDIV_MASK GENMASK(5, 0) +#define LIGHT_BYPASS_MASK BIT(30) +#define LIGHT_RST_MASK BIT(29) +#define LIGHT_DSMPD_MASK BIT(24) +#define LIGHT_DACPD_MASK BIT(25) +#define LIGHT_FRAC_MASK GENMASK(23, 0) +#define LIGHT_FRAC_SHIFT 0 +#define LIGHT_FRAC_DIV BIT(24) + +#define LOCK_TIMEOUT_US 10000 + +#define div_mask(d) ((1 << (d->width)) - 1) + +DEFINE_SPINLOCK(thead_light_clk_lock); + +enum light_pll_mode { + PLL_MODE_FRAC, + PLL_MODE_INT, +}; + +struct clk_lightpll { + struct clk_hw hw; + void __iomem *base; + enum light_pll_clktype clk_type; + enum light_pll_outtype out_type; + enum light_pll_mode pll_mode; + const struct light_pll_rate_table *rate_table; + int rate_count; + + u32 cfg0_reg_off; + u32 pll_sts_off; + int pll_lock_bit; + + /* Light MPW Aon/ddr pll define bypass:rst bits as: 31:30 + * but AP pll define bypass:rst bits as: 30:29 + * + * Light Fullmask align these register field define, all pll + * define bypss:rst bits as: 30:29 + */ + int pll_rst_bit; + int pll_bypass_bit; +}; + +struct clk_lightdiv { + struct clk_divider divider; + enum light_div_type div_type; + u16 min_div; + u16 max_div; + u8 sync_en; + const struct clk_ops *ops; +}; + +struct clk_lightgate { + struct clk_gate gate; + unsigned int *share_count; + const struct clk_ops *ops; +}; + +#define to_clk_lightpll(_hw) container_of(_hw, struct clk_lightpll, hw) + +void thead_unregister_clocks(struct clk *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + clk_unregister(clks[i]); +} + +static void clk_light_pll_cfg_init(struct clk_lightpll *pll) +{ + switch (pll->clk_type) { + case LIGHT_AUDIO_PLL: + pll->cfg0_reg_off = 0x0; + pll->pll_sts_off = 0x90; + pll->pll_lock_bit = BIT(0); + pll->pll_bypass_bit = BIT(31); + pll->pll_rst_bit = BIT(30); + pll->pll_mode = PLL_MODE_FRAC; + break; + case LIGHT_SYS_PLL: + pll->cfg0_reg_off = 0x10; + pll->pll_sts_off = 0x90; + pll->pll_lock_bit = BIT(1); + pll->pll_bypass_bit = BIT(31); + pll->pll_rst_bit = BIT(30); + pll->pll_mode = PLL_MODE_FRAC; + break; + case LIGHT_CPU_PLL0: + pll->cfg0_reg_off = 0x0; + pll->pll_sts_off = 0x80; + pll->pll_lock_bit = BIT(1); + pll->pll_bypass_bit = BIT(30); + pll->pll_rst_bit = BIT(29); + pll->pll_mode = PLL_MODE_INT; + break; + case LIGHT_CPU_PLL1: + pll->cfg0_reg_off = 0x10; + pll->pll_sts_off = 0x80; + pll->pll_lock_bit = BIT(4); + pll->pll_bypass_bit = BIT(30); + pll->pll_rst_bit = BIT(29); + pll->pll_mode = PLL_MODE_INT; + break; + case LIGHT_GMAC_PLL: + pll->cfg0_reg_off = 0x20; + pll->pll_sts_off = 0x80; + pll->pll_lock_bit = BIT(3); + pll->pll_bypass_bit = BIT(30); + pll->pll_rst_bit = BIT(29); + pll->pll_mode = PLL_MODE_INT; + break; + case LIGHT_VIDEO_PLL: + pll->cfg0_reg_off = 0x30; + pll->pll_sts_off = 0x80; + pll->pll_lock_bit = BIT(7); + pll->pll_bypass_bit = BIT(30); + pll->pll_rst_bit = BIT(29); + pll->pll_mode = PLL_MODE_INT; + break; + case LIGHT_DDR_PLL: + pll->cfg0_reg_off = 0x8; + pll->pll_sts_off = 0x18; + pll->pll_lock_bit = BIT(0); + pll->pll_bypass_bit = BIT(31); + pll->pll_rst_bit = BIT(30); + pll->pll_mode = PLL_MODE_INT; + break; + case LIGHT_DPU0_PLL: + pll->cfg0_reg_off = 0x40; + pll->pll_sts_off = 0x80; + pll->pll_lock_bit = BIT(8); + pll->pll_bypass_bit = BIT(30); + pll->pll_rst_bit = BIT(29); + pll->pll_mode = PLL_MODE_INT; + break; + case LIGHT_DPU1_PLL: + pll->cfg0_reg_off = 0x50; + pll->pll_sts_off = 0x80; + pll->pll_lock_bit = BIT(9); + pll->pll_bypass_bit = BIT(30); + pll->pll_rst_bit = BIT(29); + pll->pll_mode = PLL_MODE_INT; + break; + default: + pr_err("%s: Unknown pll type\n", __func__); + }; +} + +static int clk_light_pll_wait_lock(struct clk_lightpll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base + pll->pll_sts_off, val, + val & pll->pll_lock_bit, 0, + LOCK_TIMEOUT_US); +} + +static int clk_light_pll_prepare(struct clk_hw *hw) +{ + struct clk_lightpll *pll = to_clk_lightpll(hw); + void __iomem *cfg1_off; + u32 val; + int ret; + + cfg1_off = pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1; + val = readl_relaxed(cfg1_off); + if (!(val & pll->pll_rst_bit)) + return 0; + + /* Enable RST */ + val |= pll->pll_rst_bit; + writel_relaxed(val, cfg1_off); + + udelay(3); + + /* Disable RST */ + val &= ~pll->pll_rst_bit; + writel_relaxed(val, cfg1_off); + + ret = clk_light_pll_wait_lock(pll); + if (ret) + return ret; + + return 0; +} + +static int clk_light_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_lightpll *pll = to_clk_lightpll(hw); + u32 val; + + val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); + + return (val & pll->pll_rst_bit) ? 0 : 1; +} + +static void clk_light_pll_unprepare(struct clk_hw *hw) +{ + struct clk_lightpll *pll = to_clk_lightpll(hw); + u32 val; + + val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); + val |= pll->pll_rst_bit; + writel_relaxed(val, pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); +} + +static unsigned long clk_light_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ +#ifndef CONFIG_LIGHT_CLK_EMU + struct clk_lightpll *pll = to_clk_lightpll(hw); + u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + u32 pll_cfg0, pll_cfg1; + u64 fvco = 0; + + pll_cfg0 = readl_relaxed(pll->base + pll->cfg0_reg_off); + pll_cfg1 = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); + refdiv = (pll_cfg0 & LIGHT_REFDIV_MASK) >> LIGHT_REFDIV_SHIFT; + fbdiv = (pll_cfg0 & LIGHT_FBDIV_MASK) >> LIGHT_FBDIV_SHIFT; + postdiv1 = (pll_cfg0 & LIGHT_POSTDIV1_MASK) >> LIGHT_POSTDIV1_SHIFT; + postdiv2 = (pll_cfg0 & LIGHT_POSTDIV2_MASK) >> LIGHT_POSTDIV2_SHIFT; + frac = (pll_cfg1 & LIGHT_FRAC_MASK) >> LIGHT_FRAC_SHIFT; + + /* rate calculation: + * INT mode: FOUTVCO = FREE * FBDIV / REFDIV + * FRAC mode:FOUTVCO = (FREE * FBDIV + FREE * FRAC/BIT(24)) / REFDIV + */ + if (pll->pll_mode == PLL_MODE_FRAC) + fvco = (parent_rate * frac) / LIGHT_FRAC_DIV; + + fvco += (parent_rate * fbdiv); + do_div(fvco, refdiv); + + if (pll->out_type == LIGHT_PLL_DIV) + do_div(fvco, postdiv1 * postdiv2); + + return fvco; +#else + + struct clk_lightpll *pll = to_clk_lightpll(hw); + const struct light_pll_rate_table *rate_table = pll->rate_table; + + /* return minimum supported value */ + if (pll->out_type == LIGHT_PLL_DIV) + return rate_table[0].rate; + + return rate_table[0].vco_rate; +#endif +} + +static const struct light_pll_rate_table *light_get_pll_div_settings( + struct clk_lightpll *pll, unsigned long rate) +{ + const struct light_pll_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) + if (rate == rate_table[i].rate) + return &rate_table[i]; + + return NULL; +} + +static const struct light_pll_rate_table *light_get_pll_vco_settings( + struct clk_lightpll *pll, unsigned long rate) +{ + const struct light_pll_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) + if (rate == rate_table[i].vco_rate) + return &rate_table[i]; + + return NULL; +} + +static inline bool clk_light_pll_change(struct clk_lightpll *pll, + const struct light_pll_rate_table *rate) +{ + u32 refdiv_old, fbdiv_old, postdiv1_old, postdiv2_old, frac_old; + u32 cfg0, cfg1; + bool pll_changed; + + cfg0 = readl_relaxed(pll->base + pll->cfg0_reg_off); + cfg1 = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); + + refdiv_old = (cfg0 & LIGHT_REFDIV_MASK) >> LIGHT_REFDIV_SHIFT; + fbdiv_old = (cfg0 & LIGHT_FBDIV_MASK) >> LIGHT_FBDIV_SHIFT; + postdiv1_old = (cfg0 & LIGHT_POSTDIV1_MASK) >> LIGHT_POSTDIV1_SHIFT; + postdiv2_old = (cfg0 & LIGHT_POSTDIV2_MASK) >> LIGHT_POSTDIV2_SHIFT; + frac_old = (cfg1 & LIGHT_FRAC_MASK) >> LIGHT_FRAC_SHIFT; + + pll_changed = rate->refdiv != refdiv_old || rate->fbdiv != fbdiv_old || + rate->postdiv1 != postdiv1_old || rate->postdiv2 != postdiv2_old; + if (pll->pll_mode == PLL_MODE_FRAC) + pll_changed |= (rate->frac != frac_old); + + return pll_changed; +} + +static int clk_light_pll_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_lightpll *pll = to_clk_lightpll(hw); + const struct light_pll_rate_table *rate; + void __iomem *cfg1_off; + u32 tmp, div_val; + int ret; + + if (pll->out_type == LIGHT_PLL_VCO) { + rate = light_get_pll_vco_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + } else { + rate = light_get_pll_div_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + } + + if (!clk_light_pll_change(pll, rate)) + return 0; + + /* Enable RST */ + cfg1_off = pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1; + tmp = readl_relaxed(cfg1_off); + tmp |= pll->pll_rst_bit; + writel_relaxed(tmp, cfg1_off); + + div_val = (rate->refdiv << LIGHT_REFDIV_SHIFT) | + (rate->fbdiv << LIGHT_FBDIV_SHIFT) | + (rate->postdiv1 << LIGHT_POSTDIV1_SHIFT) | + (rate->postdiv2 << LIGHT_POSTDIV2_SHIFT); + writel_relaxed(div_val, pll->base + pll->cfg0_reg_off); + + if (pll->pll_mode == PLL_MODE_FRAC) { + tmp &= ~(LIGHT_FRAC_MASK << LIGHT_FRAC_SHIFT); + tmp |= rate->frac; + writel_relaxed(tmp, cfg1_off); + } + + udelay(3); + + /* Disable RST */ + tmp &= ~pll->pll_rst_bit; + writel_relaxed(tmp, cfg1_off); + + /* Wait Lock, ~20us cost */ + ret = clk_light_pll_wait_lock(pll); + if (ret) + return ret; + + /* HW requires 30us for pll stable */ + udelay(30); + + return 0; +} + +static long clk_light_pllvco_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_lightpll *pll = to_clk_lightpll(hw); + const struct light_pll_rate_table *rate_table = pll->rate_table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; + + for (i = 0; i < pll->rate_count; i++) { + now = rate_table[i].vco_rate; + + if (rate == now) { + return rate_table[i].vco_rate; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + /* return minimum supported value */ + return rate_table[best_i].vco_rate; +} + +static long clk_light_plldiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_lightpll *pll = to_clk_lightpll(hw); + const struct light_pll_rate_table *rate_table = pll->rate_table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; + + for (i = 0; i < pll->rate_count; i++) { + now = rate_table[i].rate; + + if (rate == now) { + return rate_table[i].rate; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + /* return minimum supported value */ + return rate_table[best_i].rate; +} + +static const struct clk_ops clk_light_pll_def_ops = { + .recalc_rate = clk_light_pll_recalc_rate, +}; + +static const struct clk_ops clk_light_pllvco_ops = { + .prepare = clk_light_pll_prepare, + .unprepare = clk_light_pll_unprepare, + .is_prepared = clk_light_pll_is_prepared, + .recalc_rate = clk_light_pll_recalc_rate, + .round_rate = clk_light_pllvco_round_rate, + .set_rate = clk_light_pll_set_rate, +}; + +static const struct clk_ops clk_light_plldiv_ops = { + .prepare = clk_light_pll_prepare, + .unprepare = clk_light_pll_unprepare, + .is_prepared = clk_light_pll_is_prepared, + .recalc_rate = clk_light_pll_recalc_rate, + .round_rate = clk_light_plldiv_round_rate, + .set_rate = clk_light_pll_set_rate, +}; + +struct clk *thead_light_pll(const char *name, const char *parent_name, + void __iomem *base, + const struct light_pll_clk *pll_clk) +{ + struct clk_lightpll *pll; + struct clk *clk; + struct clk_init_data init; + u32 val; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = pll_clk->flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + switch (pll_clk->out_type) { + case LIGHT_PLL_VCO: + if (pll_clk->rate_table) + init.ops = &clk_light_pllvco_ops; + break; + case LIGHT_PLL_DIV: + if (pll_clk->rate_table) + init.ops = &clk_light_plldiv_ops; + break; + default: + pr_err("%s: Unknown pll out type for pll clk %s\n", + __func__, name); + }; + + if (!pll_clk->rate_table) + init.ops = &clk_light_pll_def_ops; + + pll->base = base; + pll->hw.init = &init; + pll->out_type = pll_clk->out_type; + pll->clk_type = pll_clk->clk_type; + pll->rate_table = pll_clk->rate_table; + pll->rate_count = pll_clk->rate_count; + + clk_light_pll_cfg_init(pll); + + val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); + val &= ~pll->pll_bypass_bit; + val |= LIGHT_DACPD_MASK; + val |= LIGHT_DSMPD_MASK; + if (pll->pll_mode == PLL_MODE_FRAC) { + val &= ~LIGHT_DSMPD_MASK; + val &= ~LIGHT_DACPD_MASK; + } + writel_relaxed(val, pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll %s %lu\n", + __func__, name, PTR_ERR(clk)); + kfree(pll); + } + + return clk; +} + +static inline struct clk_lightdiv *to_clk_lightdiv(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_divider(hw); + + return container_of(divider, struct clk_lightdiv, divider); +} + +static unsigned long clk_lightdiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_lightdiv *light_div = to_clk_lightdiv(hw); + + return light_div->ops->recalc_rate(&light_div->divider.hw, parent_rate); +} + +static long clk_lightdiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_lightdiv *light_div = to_clk_lightdiv(hw); + + return light_div->ops->round_rate(&light_div->divider.hw, rate, prate); +} + +static int clk_lightdiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_lightdiv *light_div = to_clk_lightdiv(hw); + struct clk_divider *div = to_clk_divider(hw); + unsigned int divider, value; + unsigned long flags = 0; + u32 val; + + divider = parent_rate / rate; + + /* DIV is zero based divider, but CDE is not */ + if (light_div->div_type == MUX_TYPE_DIV) + value = divider; + else + value = divider - 1; + + /* handle the div valid range */ + if (value > light_div->max_div) + value = light_div->max_div; + if (value < light_div->min_div) + value = light_div->min_div; + + spin_lock_irqsave(div->lock, flags); + + val = readl(div->reg); + val &= ~BIT(light_div->sync_en); + writel(val, div->reg); + + udelay(1); + + val &= ~(div_mask(div) << div->shift); + val |= value << div->shift; + writel(val, div->reg); + + udelay(1); + + val |= BIT(light_div->sync_en); + writel(val, div->reg); + + spin_unlock_irqrestore(div->lock, flags); + + return 0; +} + +static const struct clk_ops clk_lightdiv_ops = { + .recalc_rate = clk_lightdiv_recalc_rate, + .round_rate = clk_lightdiv_round_rate, + .set_rate = clk_lightdiv_set_rate, +}; + +struct clk *thead_clk_light_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, + u8 sync, enum light_div_type div_type, + u16 min, u16 max) +{ + struct clk_lightdiv *light_div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + light_div = kzalloc(sizeof(*light_div), GFP_KERNEL); + if (!light_div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_lightdiv_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + + light_div->divider.reg = reg; + light_div->divider.shift = shift; + light_div->divider.width = width; + light_div->divider.lock = &thead_light_clk_lock; + light_div->divider.hw.init = &init; + light_div->ops = &clk_divider_ops; + light_div->sync_en = sync; + light_div->div_type = div_type; + if (light_div->div_type == MUX_TYPE_DIV) + light_div->divider.flags = CLK_DIVIDER_ONE_BASED; + light_div->min_div = min > ((1 << width) - 1) ? + ((1 << width) - 1) : min; + light_div->max_div = max > ((1 << width) - 1) ? + ((1 << width) - 1) : max; + + hw = &light_div->divider.hw; + + ret = clk_hw_register(NULL, hw); + if (ret) { + kfree(light_div); + return ERR_PTR(ret); + } + + return hw->clk; +} + +static inline struct clk_lightgate *to_clk_lightgate(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + + return container_of(gate, struct clk_lightgate, gate); +} + +static int clk_light_gate_share_is_enabled(struct clk_hw *hw) +{ + struct clk_lightgate *light_gate = to_clk_lightgate(hw); + + return light_gate->ops->is_enabled(hw); +} + +static int clk_light_gate_share_enable(struct clk_hw *hw) +{ + struct clk_lightgate *light_gate = to_clk_lightgate(hw); + + if (light_gate->share_count && (*light_gate->share_count)++ > 0) { + pr_debug("[%s,%d]share_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); + return 0; + } + + pr_debug("[%s,%d]share_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); + + return light_gate->ops->enable(hw); +} + +static void clk_light_gate_share_disable(struct clk_hw *hw) +{ + struct clk_lightgate *light_gate = to_clk_lightgate(hw); + + if (light_gate->share_count) { + if (WARN_ON(*light_gate->share_count == 0)) + return; + else if (--(*light_gate->share_count) > 0) { + pr_debug("[%s,%d]share_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); + return; + } + } + + pr_debug("[%s,%d]share_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); + + light_gate->ops->disable(hw); +} + +static void clk_light_gate_share_disable_unused(struct clk_hw *hw) +{ + struct clk_lightgate *light_gate = to_clk_lightgate(hw); + + if (!light_gate->share_count || *light_gate->share_count == 0) + return light_gate->ops->disable(hw); +} + +static const struct clk_ops clk_lightgate_share_ops = { + .enable = clk_light_gate_share_enable, + .disable = clk_light_gate_share_disable, + .disable_unused = clk_light_gate_share_disable_unused, + .is_enabled = clk_light_gate_share_is_enabled, +}; + +struct clk *thead_clk_light_register_gate_shared(const char *name, const char *parent, + unsigned long flags, void __iomem *reg, + u8 shift, spinlock_t *lock, + unsigned int *share_count) +{ + struct clk_lightgate *light_gate; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + light_gate = kzalloc(sizeof(*light_gate), GFP_KERNEL); + if (!light_gate) + return ERR_PTR(-ENOMEM); + + light_gate->gate.reg = reg; + light_gate->gate.bit_idx = shift; + light_gate->gate.flags = 0; + light_gate->gate.lock = lock; + light_gate->gate.hw.init = &init; + light_gate->ops = &clk_gate_ops; + light_gate->share_count = share_count; + + init.name = name; + init.ops = &clk_lightgate_share_ops; + init.flags = flags; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + + hw = &light_gate->gate.hw; + + ret = clk_hw_register(NULL, hw); + if (ret) { + kfree(light_gate); + return ERR_PTR(ret); + } + + return hw->clk; +} diff --git a/drivers/clk/thead/clk.h b/drivers/clk/thead/clk.h new file mode 100644 index 00000000000000..cad975e8ede455 --- /dev/null +++ b/drivers/clk/thead/clk.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#ifndef __MACH_THEAD_CLK_H +#define __MACH_THEAD_CLK_H + +#include +#include + +extern spinlock_t thead_light_clk_lock; + +#define LIGHT_PLL_RATE(_vco, _rate, _r, _b, _f, _p, _k) \ + { \ + .vco_rate = (_vco), \ + .rate = (_rate), \ + .refdiv = (_r), \ + .fbdiv = (_b), \ + .frac = (_f), \ + .postdiv1 = (_p), \ + .postdiv2 = (_k), \ + } + +enum light_pll_outtype { + LIGHT_PLL_VCO, + LIGHT_PLL_DIV, +}; + +enum light_div_type { + MUX_TYPE_DIV, + MUX_TYPE_CDE, +}; + +enum light_pll_clktype { + LIGHT_AUDIO_PLL, + LIGHT_SYS_PLL, + LIGHT_CPU_PLL0, + LIGHT_CPU_PLL1, + LIGHT_GMAC_PLL, + LIGHT_VIDEO_PLL, + LIGHT_DDR_PLL, + LIGHT_DPU0_PLL, + LIGHT_DPU1_PLL, +}; + +struct light_pll_rate_table { + unsigned long vco_rate; + unsigned long rate; + unsigned int refdiv; + unsigned int fbdiv; + unsigned int frac; + unsigned int postdiv1; + unsigned int postdiv2; +}; + +struct light_pll_clk { + enum light_pll_outtype out_type; + enum light_pll_clktype clk_type; + const struct light_pll_rate_table *rate_table; + int rate_count; + int flags; +}; + +static inline struct clk *thead_light_clk_fixed_factor(const char *name, + const char *parent, unsigned int mult, unsigned int div) +{ + return clk_register_fixed_factor(NULL, name, parent, + CLK_SET_RATE_PARENT, mult, div); +} + +struct clk *thead_light_pll(const char *name, const char *parent_name, + void __iomem *base, + const struct light_pll_clk *pll_clk); + +static inline struct clk *thead_clk_light_gate(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &thead_light_clk_lock); +} + +struct clk *thead_clk_light_register_gate_shared(const char *name, const char *parent, + unsigned long flags, void __iomem *reg, + u8 shift, spinlock_t *lock, + unsigned int *share_count); + +struct clk *thead_clk_light_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, + u8 sync, enum light_div_type div_type, + u16 min, u16 max); + +void thead_unregister_clocks(struct clk *clks[], unsigned int count); + +static inline struct clk *thead_clk_fixed(const char *name, unsigned long rate) +{ + return clk_register_fixed_rate(NULL, name, NULL, 0, rate); +} + +static inline struct clk *thead_clk_light_gate_shared(const char *name, const char *parent, + void __iomem *reg, u8 shift, + unsigned int *share_count) +{ + return thead_clk_light_register_gate_shared(name, parent, CLK_SET_RATE_PARENT, reg, + shift, &thead_light_clk_lock, share_count); +} + +static inline struct clk *thead_light_clk_mux_flags(const char *name, + void __iomem *reg, u8 shift, u8 width, + const char * const *parents, int num_parents, + unsigned long flags) +{ + return clk_register_mux(NULL, name, parents, num_parents, + flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0, + &thead_light_clk_lock); +} +#endif diff --git a/drivers/clk/thead/gate/Makefile b/drivers/clk/thead/gate/Makefile new file mode 100644 index 00000000000000..b0ad8b2011c053 --- /dev/null +++ b/drivers/clk/thead/gate/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_CLK_LIGHT_FM) += thead-gate.o visys-gate.o vpsys-gate.o vosys-gate.o dspsys-gate.o diff --git a/drivers/clk/thead/gate/clk-gate.h b/drivers/clk/thead/gate/clk-gate.h new file mode 100644 index 00000000000000..ebb190374a0edc --- /dev/null +++ b/drivers/clk/thead/gate/clk-gate.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#ifndef CLK_GATE_H +#define CLK_GATE_H + +#include +#include + +enum clk_gate_type { + GATE_NOT_SHARED, + GATE_SHARED, +}; + +struct thead_clk_gate { + struct clk_hw hw; + struct regmap *regmap; + u32 offset; + u8 bit; + bool shared; + u32 *share_count; +}; + +struct clk *thead_gate_clk_register(const char *name, + const char *parent_name, + struct regmap *regmap, + int offset, + u8 bit, + bool shared, + u32 *share_count, + struct device *dev); + +#endif diff --git a/drivers/clk/thead/gate/dspsys-gate.c b/drivers/clk/thead/gate/dspsys-gate.c new file mode 100644 index 00000000000000..e68a5d4e6151e1 --- /dev/null +++ b/drivers/clk/thead/gate/dspsys-gate.c @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk-gate.h" +#include "../clk.h" + +static struct clk *gates[LIGHT_CLKGEN_DSPSYS_CLK_END]; +static struct clk_onecell_data clk_gate_data; + +static int light_dspsys_clk_probe(struct platform_device *pdev) +{ + struct regmap *dspsys_regmap, *tee_dspsys_regmap; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + int ret; + + dspsys_regmap = syscon_regmap_lookup_by_phandle(np, "dspsys-regmap"); + if (IS_ERR(dspsys_regmap)) { + dev_err(&pdev->dev, "cannot find regmap for dsp system register\n"); + return PTR_ERR(dspsys_regmap); + } + + tee_dspsys_regmap = syscon_regmap_lookup_by_phandle(np, "tee-dspsys-regmap"); + if (IS_ERR(tee_dspsys_regmap)) { + dev_warn(&pdev->dev, "cannot find regmap for tee dsp system register\n"); + tee_dspsys_regmap = NULL; + } + + gates[CLKGEN_DSP0_PCLK] = thead_gate_clk_register("clkgen_dsp0_pclk", NULL, dspsys_regmap, + 0x24, 0, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_DSP1_PCLK] = thead_gate_clk_register("clkgen_dsp1_pclk", NULL, dspsys_regmap, + 0x24, 1, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_DSP1_CCLK] = thead_gate_clk_register("clkgen_dsp1_cclk", NULL, dspsys_regmap, + 0x24, 2, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_DSP0_CCLK] = thead_gate_clk_register("clkgen_dsp0_cclk", NULL, dspsys_regmap, + 0x24, 3, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_X2X_DSP2_ACLK_S] = thead_gate_clk_register("clkgen_x2x_dsp2_aclk_s", NULL, dspsys_regmap, + 0x24, 4, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_X2X_DSP0_ACLK_S] = thead_gate_clk_register("clkgen_x2x_dsp0_aclk_s", NULL, dspsys_regmap, + 0x24, 5, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_X2X_X4_DSPSLV_DSP1_ACLK_M] = thead_gate_clk_register("clkgen_x2x_x4_dspslv_dsp1_aclk_m", + NULL, dspsys_regmap, 0x24, 6, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_X2X_X4_DSPSLV_DSP0_ACLK_M] = thead_gate_clk_register("clkgen_x2x_x4_dspslv_dsp0_aclk_m", + NULL, dspsys_regmap, 0x24, 7, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_AXI4_DSPSYS_SLV_ACLK] = thead_gate_clk_register("clkgen_axi4_dspsys_slv_aclk", NULL, dspsys_regmap, + 0x24, 20, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_AXI4_DSPSYS_SLV_PCLK] = thead_gate_clk_register("clkgen_axi4_dspsys_slv_pclk", NULL, dspsys_regmap, + 0x24, 21, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_AXI4_DSPSYS_ACLK] = thead_gate_clk_register("clkgen_axi4_dspsys_aclk", NULL, dspsys_regmap, + 0x24, 23, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_AXI4_DSPSYS_PCLK] = thead_gate_clk_register("clkgen_axi4_dspsys_pclk", NULL, dspsys_regmap, + 0x24, 24, GATE_NOT_SHARED, NULL, dev); + if (tee_dspsys_regmap) { + gates[CLKGEN_IOPMP_DSP1_PCLK] = thead_gate_clk_register("clkgen_iopmp_dsp1_pclk", NULL, tee_dspsys_regmap, + 0x24, 25, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_IOPMP_DSP0_PCLK] = thead_gate_clk_register("clkgen_iopmp_dsp0_pclk", NULL, tee_dspsys_regmap, + 0x24, 26, GATE_NOT_SHARED, NULL, dev); + } + + clk_gate_data.clks = gates; + clk_gate_data.clk_num = ARRAY_SIZE(gates); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); + if (ret < 0) { + dev_err(dev, "failed to register gate clks for light dspsys\n"); + goto unregister_clks; + } + + dev_info(dev, "succeed to register dspsys gate clock provider\n"); + + return 0; + +unregister_clks: + thead_unregister_clocks(gates, ARRAY_SIZE(gates)); + return ret; +} + +static const struct of_device_id dspsys_clk_gate_of_match[] = { + { .compatible = "thead,dspsys-gate-controller" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, dspsys_clk_gate_of_match); + +static struct platform_driver light_dspsys_clk_driver = { + .probe = light_dspsys_clk_probe, + .driver = { + .name = "dspsys-clk-gate-provider", + .of_match_table = of_match_ptr(dspsys_clk_gate_of_match), + }, +}; + +module_platform_driver(light_dspsys_clk_driver); +MODULE_AUTHOR("wei.liu "); +MODULE_DESCRIPTION("Thead Light Fullmask dspsys clock gate provider"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/thead/gate/thead-gate.c b/drivers/clk/thead/gate/thead-gate.c new file mode 100644 index 00000000000000..372c11dee1b989 --- /dev/null +++ b/drivers/clk/thead/gate/thead-gate.c @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk-gate.h" + +#define to_thead_clk_gate(_hw) container_of(_hw, struct thead_clk_gate, hw) + +static int thead_clk_gate_is_enabled(struct clk_hw *hw) +{ + struct thead_clk_gate *tcg = to_thead_clk_gate(hw); + u32 val; + + regmap_read(tcg->regmap, tcg->offset, &val); + + val &= BIT(tcg->bit); + + return val != 0; +} + +static void thead_clk_gate_disable(struct clk_hw *hw) +{ + struct thead_clk_gate *tcg = to_thead_clk_gate(hw); + + if (!tcg->shared) + goto out; + + if (tcg->share_count) { + if (WARN_ON(*tcg->share_count == 0)) + return; + else if (--(*tcg->share_count) > 0) { + pr_info("[%s,%d]share_count = %d\n", __func__, __LINE__, + (*tcg->share_count)); + return; + } + } + +out: + regmap_update_bits(tcg->regmap, tcg->offset, + BIT(tcg->bit), 0); +} + +static int thead_clk_gate_enable(struct clk_hw *hw) +{ + struct thead_clk_gate *tcg = to_thead_clk_gate(hw); + + if (!tcg->shared) + goto out; + + if (tcg->share_count && (*tcg->share_count)++ > 0) { + pr_info("[%s,%d]share_count = %d\n", __func__, __LINE__, (*tcg->share_count)); + return 0; + } + +out: + return regmap_update_bits(tcg->regmap, tcg->offset, + BIT(tcg->bit), BIT(tcg->bit)); +} + +const struct clk_ops thead_gate_clk_ops = { + .enable = thead_clk_gate_enable, + .disable = thead_clk_gate_disable, + .is_enabled = thead_clk_gate_is_enabled, +}; + +struct clk *thead_gate_clk_register(const char *name, + const char *parent_name, + struct regmap *regmap, + int offset, + u8 bit, + bool shared, + u32 *share_count, + struct device *dev) +{ + struct thead_clk_gate *tcg; + struct clk *clk; + struct clk_init_data init = {}; + + tcg = kzalloc(sizeof(*tcg), GFP_KERNEL); + if (!tcg) + return ERR_PTR(-ENOMEM); + + tcg->regmap = regmap; + tcg->offset = offset; + tcg->bit = bit; + tcg->shared = shared; + tcg->share_count = share_count; + + init.name = name; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.ops = &thead_gate_clk_ops; + + tcg->hw.init = &init; + + clk = clk_register(dev, &tcg->hw); + if (IS_ERR(clk)) + kfree(tcg); + + return clk; +} diff --git a/drivers/clk/thead/gate/visys-gate.c b/drivers/clk/thead/gate/visys-gate.c new file mode 100644 index 00000000000000..b023e42b826956 --- /dev/null +++ b/drivers/clk/thead/gate/visys-gate.c @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk-gate.h" +#include "../clk.h" + +static struct clk *gates[LIGHT_CLKGEN_VISYS_CLK_END]; +static struct clk_onecell_data clk_gate_data; + +static u32 share_cnt_isp0_hclk_en; +static u32 share_cnt_isp0_aclk_en; + +static int light_visys_clk_probe(struct platform_device *pdev) +{ + struct regmap *visys_regmap; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + int ret; + + visys_regmap = syscon_regmap_lookup_by_phandle(np, "visys-regmap"); + if (IS_ERR(visys_regmap)) { + dev_err(&pdev->dev, "cannot find regmap for vi system register\n"); + return PTR_ERR(visys_regmap); + } + + /* we assume that the gate clock is a root clock */ + gates[LIGHT_CLKGEN_DW200_ACLK] = thead_gate_clk_register("clkgen_dw200_aclk", NULL, + visys_regmap, 0xa0, 27, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_AXI4_VISYS1_ACLK] = thead_gate_clk_register("clkgen_axi4_visys1_aclk", NULL, + visys_regmap, 0xa0, 26, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_AXI4_VISYS2_ACLK] = thead_gate_clk_register("clkgen_axi4_visys2_aclk", NULL, + visys_regmap, 0xa0, 25, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_AXI4_VISYS3_ACLK] = thead_gate_clk_register("clkgen_axi4_visys3_aclk", NULL, + visys_regmap, 0xa0, 24, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_RY_ACLK] = thead_gate_clk_register("clkgen_isp_ry_aclk", NULL, + visys_regmap, 0xa0, 22, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK] = thead_gate_clk_register("clkgen_isp_venc_shake_aclk", NULL, + visys_regmap, 0xa0, 30, GATE_NOT_SHARED, NULL, dev); + + gates[LIGHT_CLKGEN_VIPRE_ACLK] = thead_gate_clk_register("clkgen_vipre_aclk", NULL, + visys_regmap, 0xa0, 31, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_DW200_HCLK] = thead_gate_clk_register("clkgen_dw200_hclk", NULL, + visys_regmap, 0xa0, 13, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_RY_HCLK] = thead_gate_clk_register("clkgen_isp_ry_hclk", NULL, + visys_regmap, 0xa0, 12, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI0_PCLK] = thead_gate_clk_register("clkgen_mipi_csi0_pclk", NULL, + visys_regmap, 0xa0, 18, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI1_PCLK] = thead_gate_clk_register("clkgen_mipi_csi1_pclk", NULL, + visys_regmap, 0xa0, 17, GATE_NOT_SHARED, NULL, dev); + + gates[LIGHT_CLKGEN_MIPI_CSI2_PCLK] = thead_gate_clk_register("clkgen_mipi_csi2_pclk", NULL, + visys_regmap, 0xa0, 16, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_VIPRE_PCLK] = thead_gate_clk_register("clkgen_vipre_pclk", NULL, + visys_regmap, 0xa0, 15, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK] = thead_gate_clk_register("clkgen_isp_venc_shake_pclk", NULL, + visys_regmap, 0xa0, 29, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI0_PIXCLK] = thead_gate_clk_register("clkgen_mipi_csi0_pixclk", NULL, + visys_regmap, 0xa0, 11, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI1_PIXCLK] = thead_gate_clk_register("clkgen_mipi_csi1_pixclk", NULL, + visys_regmap, 0xa0, 10, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI2_PIXCLK] = thead_gate_clk_register("clkgen_mipi_csi2_pixclk", NULL, + visys_regmap, 0xa0, 9, GATE_NOT_SHARED, NULL, dev); + + gates[LIGHT_CLKGEN_VIPRE_PIXELCLK] = thead_gate_clk_register("clkgen_vipre_pixelclk", NULL, + visys_regmap, 0xa4, 23, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI0_CFG_CLK] = thead_gate_clk_register("clkgen_mipi_csi0_cfg_clk", NULL, + visys_regmap, 0xa0, 8, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI1_CFG_CLK] = thead_gate_clk_register("clkgen_mipi_csi1_cfg_clk", NULL, + visys_regmap, 0xa0, 6, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI2_CFG_CLK] = thead_gate_clk_register("clkgen_mipi_csi2_cfg_clk", NULL, + visys_regmap, 0xa0, 7, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_DW200_CLK_VSE] = thead_gate_clk_register("clkgen_dw200_clk_vse", NULL, + visys_regmap, 0xa0, 5, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_DW200_CLK_DWE] = thead_gate_clk_register("clkgen_dw200_clk_dwe", NULL, + visys_regmap, 0xa0, 4, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP0_CLK] = thead_gate_clk_register("clkgen_isp_clk_0", NULL, + visys_regmap, 0xa4, 31, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP1_CLK] = thead_gate_clk_register("clkgen_isp_clk_1", NULL, + visys_regmap, 0xa4, 30, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_RY_CCLK] = thead_gate_clk_register("clkgen_isp_ry_cclk", NULL, + visys_regmap, 0xa0, 21, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP1_PIXELCLK] = thead_gate_clk_register("clkgen_isp1_pixelclk", NULL, + visys_regmap, 0xa4, 28, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP0_PIXELCLK] = thead_gate_clk_register("clkgen_isp0_pixelclk", NULL, + visys_regmap, 0xa4, 29, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP1_HCLK] = thead_gate_clk_register("clkgen_isp1_hclk", NULL, + visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); + gates[LIGHT_CLKGEN_ISP0_HCLK] = thead_gate_clk_register("clkgen_isp0_hclk", NULL, + visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); + gates[LIGHT_CLKGEN_ISP1_ACLK] = thead_gate_clk_register("clkgen_isp1_aclk", NULL, + visys_regmap, 0xa0, 3, GATE_SHARED, &share_cnt_isp0_aclk_en, dev); + gates[LIGHT_CLKGEN_ISP0_ACLK] = thead_gate_clk_register("clkgen_isp0_aclk", NULL, + visys_regmap, 0xa0, 3, GATE_SHARED, &share_cnt_isp0_aclk_en, dev); + + clk_gate_data.clks = gates; + clk_gate_data.clk_num = ARRAY_SIZE(gates); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); + if (ret < 0) { + dev_err(dev, "failed to register gate clks for light visys\n"); + goto unregister_clks; + } + + dev_info(dev, "succeed to register visys gate clock provider\n"); + + return 0; + +unregister_clks: + thead_unregister_clocks(gates, ARRAY_SIZE(gates)); + return ret; +} + +static const struct of_device_id visys_clk_gate_of_match[] = { + { .compatible = "thead,visys-gate-controller" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, visys_clk_gate_of_match); + +static struct platform_driver light_visys_clk_driver = { + .probe = light_visys_clk_probe, + .driver = { + .name = "visys-clk-gate-provider", + .of_match_table = of_match_ptr(visys_clk_gate_of_match), + }, +}; + +module_platform_driver(light_visys_clk_driver); +MODULE_AUTHOR("wei.liu "); +MODULE_DESCRIPTION("Thead Light Fullmask visys clock gate provider"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/thead/gate/vosys-gate.c b/drivers/clk/thead/gate/vosys-gate.c new file mode 100644 index 00000000000000..e53ba1a3e763a6 --- /dev/null +++ b/drivers/clk/thead/gate/vosys-gate.c @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../clk.h" + +static struct clk *gates[LIGHT_CLKGEN_VOSYS_CLK_END]; +static struct clk_onecell_data clk_gate_data; + +static int light_vosys_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *gate_base; + int ret; + + gate_base = devm_platform_ioremap_resource(pdev, 0); + if (WARN_ON(IS_ERR(gate_base))) + return PTR_ERR(gate_base); + + /* we assume that the gate clock is a root clock */ + gates[LIGHT_CLKGEN_AXI4_VO_PCLK] = thead_clk_light_gate("clkgen_axi4_vo_pclk", NULL, + gate_base + 0x50, 22); + gates[LIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK] = thead_clk_light_gate("clkgen_iopmp_dpu_pclk", NULL, + gate_base + 0x50, 23); + gates[LIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK] = thead_clk_light_gate("clkgen_iopmp_dpu1_pclk", NULL, + gate_base + 0x50, 24); + gates[LIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK] = thead_clk_light_gate("clkgen_iopmp_gpu_pclk", NULL, + gate_base + 0x50, 25); + gates[LIGHT_CLKGEN_HDMI_PCLK] = thead_clk_light_gate("clkgen_hdmi_pclk", NULL, gate_base + 0x50, 11); + gates[LIGHT_CLKGEN_MIPIDSI0_PCLK] = thead_clk_light_gate("clkgen_mipidsi0_pclk", NULL, + gate_base + 0x50, 13); + gates[LIGHT_CLKGEN_MIPIDSI1_PCLK] = thead_clk_light_gate("clkgen_mipidsi1_pclk", NULL, + gate_base + 0x50, 14); + gates[LIGHT_CLKGEN_AXI4_VO_ACLK] = thead_clk_light_gate("clkgen_axi4_vo_aclk", NULL, + gate_base + 0x50, 0); + gates[LIGHT_CLKGEN_IOPMP_GPU_ACLK] = thead_clk_light_gate("clkgen_iopmp_gpu_aclk", NULL, + gate_base + 0x50, 29); + gates[LIGHT_CLKGEN_IOPMP_DPU_ACLK] = thead_clk_light_gate("clkgen_iopmp_dpu_aclk", NULL, + gate_base + 0x50, 28); + gates[LIGHT_CLKGEN_IOPMP_DPU1_ACLK] = thead_clk_light_gate("clkgen_iopmp_dpu1_aclk", NULL, + gate_base + 0x50, 27); + gates[LIGHT_CLKGEN_X2H_DPU_ACLK] = thead_clk_light_gate("clkgen_x2h_dpu_aclk", NULL, gate_base + 0x50, 21); + gates[LIGHT_CLKGEN_X2H_DPU1_ACLK] = thead_clk_light_gate("clkgen_x2h_dpu1_aclk", NULL, gate_base + 0x50, 20); + gates[LIGHT_CLKGEN_MIPIDSI0_PIXCLK] = thead_clk_light_gate("clkgen_mipidsi0_pixclk", NULL, gate_base + 0x50, 30); + gates[LIGHT_CLKGEN_HDMI_PIXCLK] = thead_clk_light_gate("clkgen_hdmi_pixclk", NULL, gate_base + 0x54, 0); + gates[LIGHT_CLKGEN_MIPIDSI1_PIXCLK] = thead_clk_light_gate("clkgen_mipidsi1_pixclk", NULL, gate_base + 0x50, 31); + gates[LIGHT_CLKGEN_HDMI_SFR_CLK] = thead_clk_light_gate("clkgen_hdmi_sfr_clk", NULL, gate_base + 0x50, 10); + gates[LIGHT_CLKGEN_HDMI_CEC_CLK] = thead_clk_light_gate("clkgen_hdmi_cec_cclk", NULL, gate_base + 0x50, 12); + gates[LIGHT_CLKGEN_HDMI_I2S_CLK] = thead_clk_light_gate("clkgen_hdmi_i2s_clk", NULL, gate_base + 0x50, 19); + gates[LIGHT_CLKGEN_MIPIDSI0_CFG_CLK] = thead_clk_light_gate("clkgen_mipidsi0_cfg_clk", NULL, gate_base + 0x50, 15); + gates[LIGHT_CLKGEN_MIPIDSI1_CFG_CLK] = thead_clk_light_gate("clkgen_mipidsi1_cfg_clk", NULL, gate_base + 0x50, 16); + gates[LIGHT_CLKGEN_MIPIDSI0_REFCLK] = thead_clk_light_gate("clkgen_mipidsi0_refclk", NULL, gate_base + 0x50, 17); + gates[LIGHT_CLKGEN_MIPIDSI1_REFCLK] = thead_clk_light_gate("clkgen_mipidsi1_refclk", NULL, gate_base + 0x50, 18); + gates[LIGHT_CLKGEN_GPU_CORE_CLK] = thead_clk_light_gate("clkgen_gpu_core_clk", NULL, gate_base + 0x50, 3); + gates[LIGHT_CLKGEN_GPU_CFG_ACLK] = thead_clk_light_gate("clkgen_gpu_cfg_aclk", NULL, gate_base + 0x50, 4); + gates[LIGHT_CLKGEN_DPU_HCLK] = thead_clk_light_gate("clkgen_dpu_hclk", NULL, gate_base + 0x50, 7); + gates[LIGHT_CLKGEN_DPU_ACLK] = thead_clk_light_gate("clkgen_dpu_aclk", NULL, gate_base + 0x50, 8); + gates[LIGHT_CLKGEN_DPU_CCLK] = thead_clk_light_gate("clkgen_dpu_cclk", NULL, gate_base + 0x50, 9); + gates[LIGHT_CLKGEN_DPU_PIXCLK0] = thead_clk_light_gate("clkgen_dpu_pixclk0", NULL, gate_base + 0x50, 5); + gates[LIGHT_CLKGEN_DPU_PIXCLK1] = thead_clk_light_gate("clkgen_dpu_pixclk1", NULL, gate_base + 0x50, 6); + + clk_gate_data.clks = gates; + clk_gate_data.clk_num = ARRAY_SIZE(gates); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); + if (ret < 0) { + dev_err(dev, "failed to register gate clks for light vosys\n"); + goto unregister_clks; + } + + dev_info(dev, "succeed to register vosys gate clock provider\n"); + + return 0; + +unregister_clks: + thead_unregister_clocks(gates, ARRAY_SIZE(gates)); + return ret; +} + +static const struct of_device_id vosys_clk_gate_of_match[] = { + { .compatible = "thead,vosys-gate-controller" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, vosys_clk_gate_of_match); + +static struct platform_driver light_vosys_clk_driver = { + .probe = light_vosys_clk_probe, + .driver = { + .name = "vosys-clk-gate-provider", + .of_match_table = of_match_ptr(vosys_clk_gate_of_match), + }, +}; + +module_platform_driver(light_vosys_clk_driver); +MODULE_AUTHOR("wei.liu "); +MODULE_DESCRIPTION("Thead Light Fullmask vosys clock gate provider"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/thead/gate/vpsys-gate.c b/drivers/clk/thead/gate/vpsys-gate.c new file mode 100644 index 00000000000000..78613188da70aa --- /dev/null +++ b/drivers/clk/thead/gate/vpsys-gate.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../clk.h" + +static struct clk *gates[LIGHT_VPSYS_CLK_END]; +static struct clk_onecell_data clk_gate_data; + +static u32 share_cnt_g2d_clk_en; +static u32 share_cnt_fce_clk_en; + +static int light_vpsys_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *gate_base; + int ret; + + gate_base = devm_platform_ioremap_resource(pdev, 0); + if (WARN_ON(IS_ERR(gate_base))) + return PTR_ERR(gate_base); + + /* we assume that the gate clock is a root clock */ + gates[LIGHT_VPSYS_G2D_PCLK] = thead_clk_light_gate_shared("clkgen_vpsys_g2d_pclk", NULL, + gate_base + 0x20, 3, &share_cnt_g2d_clk_en); + gates[LIGHT_VPSYS_G2D_ACLK] = thead_clk_light_gate_shared("clkgen_vpsys_g2d_aclk", NULL, + gate_base + 0x20, 3, &share_cnt_g2d_clk_en); + gates[LIGHT_VPSYS_G2D_CCLK] = thead_clk_light_gate_shared("clkgen_vpsys_g2d_cclk", NULL, + gate_base + 0x20, 3, &share_cnt_g2d_clk_en); + + + gates[LIGHT_VPSYS_FCE_PCLK] = thead_clk_light_gate_shared("clkgen_vpsys_fce_pclk", NULL, + gate_base + 0x20, 2, &share_cnt_fce_clk_en); + gates[LIGHT_VPSYS_FCE_ACLK] = thead_clk_light_gate_shared("clkgen_vpsys_fce_aclk", NULL, + gate_base + 0x20, 2, &share_cnt_fce_clk_en); + + gates[LIGHT_VPSYS_VDEC_ACLK] = thead_clk_light_gate("clkgen_vdec_aclk", NULL, gate_base + 0x20, 4); + gates[LIGHT_VPSYS_VDEC_CCLK] = thead_clk_light_gate("clkgen_vdec_cclk", NULL, gate_base + 0x20, 5); + gates[LIGHT_VPSYS_VDEC_PCLK] = thead_clk_light_gate("clkgen_vdec_pclk", NULL, gate_base + 0x20, 6); + + gates[LIGHT_VPSYS_VENC_CCLK] = thead_clk_light_gate("clkgen_venc_cclk", NULL, gate_base + 0x20, 8); + gates[LIGHT_VPSYS_VENC_PCLK] = thead_clk_light_gate("clkgen_venc_pclk", NULL, gate_base + 0x20, 9); + gates[LIGHT_VPSYS_VENC_ACLK] = thead_clk_light_gate("clkgen_venc_aclk", NULL, gate_base + 0x20, 7); + + clk_gate_data.clks = gates; + clk_gate_data.clk_num = ARRAY_SIZE(gates); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); + if (ret < 0) { + dev_err(dev, "failed to register gate clks for light vpsys\n"); + goto unregister_clks; + } + + dev_info(dev, "succeed to register vpsys gate clock provider\n"); + + return 0; + +unregister_clks: + thead_unregister_clocks(gates, ARRAY_SIZE(gates)); + return ret; +} + +static const struct of_device_id vpsys_clk_gate_of_match[] = { + { .compatible = "thead,vpsys-gate-controller" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, vpsys_clk_gate_of_match); + +static struct platform_driver light_vpsys_clk_driver = { + .probe = light_vpsys_clk_probe, + .driver = { + .name = "vpsys-clk-gate-provider", + .of_match_table = of_match_ptr(vpsys_clk_gate_of_match), + }, +}; + +module_platform_driver(light_vpsys_clk_driver); +MODULE_AUTHOR("wei.liu "); +MODULE_DESCRIPTION("Thead Light Fullmask vpsys clock gate provider"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index f429b9b37b76c7..0c61e7d7f8c721 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -312,5 +312,15 @@ config QORIQ_CPUFREQ This adds the CPUFreq driver support for Freescale QorIQ SoCs which are capable of changing the CPU's frequency dynamically. +config RISV_THEAD_LIGHT_CPUFREQ + tristate "CPU frequency scaling driver for Thead light SoCs" + depends on OF && COMMON_CLK + select CLK_LIGHT + select PM_OPP + help + This adds the CPUFreq driver support for Thead light SoCs + which are capable of changing the CPU's frequency dynamically. + + endif endmenu diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ef851077491311..379fac60bb1655 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -107,3 +107,4 @@ obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o +obj-$(CONFIG_RISV_THEAD_LIGHT_CPUFREQ) += light-mpw-cpufreq.o diff --git a/drivers/cpufreq/light-mpw-cpufreq.c b/drivers/cpufreq/light-mpw-cpufreq.c new file mode 100644 index 00000000000000..6eb268193f299a --- /dev/null +++ b/drivers/cpufreq/light-mpw-cpufreq.c @@ -0,0 +1,490 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct atomic_notifier_head panic_notifier_list; + +static DEFINE_MUTEX(cpufreq_lock); + +bool cpufreq_denied = false; + +struct regulator *dvdd_cpu_reg; +struct regulator *dvddm_cpu_reg; + +enum LIGHT_MPW_CPUFREQ_CLKS { + LIGHT_C910_CCLK, + LIGHT_C910_CCLK_I0, + LIGHT_CPU_PLL1_FOUTPOSTDIV, + LIGHT_CPU_PLL0_FOUTPOSTDIV, +}; + +#define LIGHT_MPW_CPUFREQ_CLK_NUM 4 +#define LIGHT_CPUFREQ_THRE 2000000 +#define LIGHT_C910_BUS_CLK_SYNC BIT(11) +#define LIGHT_C910_BUS_CLK_RATIO_MASK 0x700 +#define LIGHT_C910_BUS_CLK_DIV_RATIO_2 0x100 +#define LIGHT_C910_BUS_CLK_DIV_RATIO_3 0x200 + +static int num_clks; +static struct clk_bulk_data clks[] = { + { .id = "c910_cclk" }, + { .id = "c910_cclk_i0" }, + { .id = "cpu_pll1_foutpostdiv" }, + { .id = "cpu_pll0_foutpostdiv" }, +}; + +static struct device *cpu_dev; +static struct cpufreq_frequency_table *freq_table; +static unsigned int max_freq; +static unsigned int transition_latency; +static void __iomem *ap_sys_reg; +static bool light_dvfs_sv = false; + +static u32 *light_dvddm_volt; +static u32 soc_opp_count = 0; + +static int light_set_target(struct cpufreq_policy *policy, unsigned int index) +{ + struct dev_pm_opp *opp; + unsigned long freq_hz; + int volt, volt_old; + unsigned int old_freq, new_freq; + int ret; + u32 val; + u32 re_modify_bus_freq = 0; + + mutex_lock(&cpufreq_lock); + + if (cpufreq_denied) { + dev_emerg(cpu_dev, "Denied to set cpu frequency temporarily on reboot\n"); + mutex_unlock(&cpufreq_lock); + return 0; + } + new_freq = freq_table[index].frequency; + freq_hz = new_freq * 1000; + old_freq = policy->cur; + + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); + if (IS_ERR(opp)) { + dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); + mutex_unlock(&cpufreq_lock); + return PTR_ERR(opp); + } + + volt = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); + + volt_old = regulator_get_voltage(dvdd_cpu_reg); + if (volt_old < 0) { + dev_err(cpu_dev, "failed to get cpu voltage\n"); + mutex_unlock(&cpufreq_lock); + return volt_old; + } + + dev_dbg(cpu_dev, "%u MHz, %d mV --> %u MHz, %d mV\n", + old_freq / 1000, volt_old / 1000, + new_freq / 1000, volt / 1000); + + /* change AXI bus clock ratio to match: BUS_CLK = CPU_CCLK/ratio <= 750MHz */ + val = readl(ap_sys_reg); + if (new_freq > LIGHT_CPUFREQ_THRE) { + val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; + val |= LIGHT_C910_BUS_CLK_DIV_RATIO_3; + } else { + val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; + + if (old_freq > LIGHT_CPUFREQ_THRE) { + re_modify_bus_freq = 1; + val |= LIGHT_C910_BUS_CLK_DIV_RATIO_3; + }else + val |= LIGHT_C910_BUS_CLK_DIV_RATIO_2; + } + + writel(val, ap_sys_reg); + val &= ~LIGHT_C910_BUS_CLK_SYNC; + writel(val, ap_sys_reg); + udelay(1); + val |= LIGHT_C910_BUS_CLK_SYNC; + writel(val, ap_sys_reg); + udelay(1); + + /* scaling up? scale voltage before frequency */ + if (new_freq > old_freq && !light_dvfs_sv) { + ret = regulator_set_voltage_tol(dvddm_cpu_reg, light_dvddm_volt[index], 0); + if (ret) { + dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); + mutex_unlock(&cpufreq_lock); + return ret; + } + ret = regulator_set_voltage_tol(dvdd_cpu_reg, volt, 0); + if (ret) { + dev_err(cpu_dev, + "failed to scale vddarm up: %d\n", ret); + mutex_unlock(&cpufreq_lock); + return ret; + } + } + + if (!strcmp(__clk_get_name(clk_get_parent(clks[LIGHT_C910_CCLK].clk)), + __clk_get_name(clks[LIGHT_C910_CCLK_I0].clk))) { + clk_prepare_enable(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk, new_freq * 1000); + ret = clk_set_parent(clks[LIGHT_C910_CCLK].clk, clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk); + udelay(1); + clk_disable_unprepare(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk); + } else { + clk_prepare_enable(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk, new_freq * 1000); + ret = clk_set_parent(clks[LIGHT_C910_CCLK].clk, clks[LIGHT_C910_CCLK_I0].clk); + udelay(1); + clk_disable_unprepare(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk); + } + + /*add delay for clk-switch*/ + udelay(1); + + /* Ensure the c910_cclk clock divider is what we expect */ + ret = clk_set_rate(clks[LIGHT_C910_CCLK].clk, new_freq * 1000); + if (ret) { + int ret1; + + dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); + ret1 = regulator_set_voltage_tol(dvdd_cpu_reg, volt_old, 0); + if (ret1) + dev_err(cpu_dev, "failed to restore dvdd_cpu voltage: %d\n", ret1); + mutex_unlock(&cpufreq_lock); + return ret; + } + + /* scaling down? scale voltage after frequency */ + if (new_freq < old_freq && !light_dvfs_sv) { + ret = regulator_set_voltage_tol(dvddm_cpu_reg, light_dvddm_volt[index], 0); + if (ret) + dev_err(cpu_dev, "failed to scale dvddm down: %d\n", ret); + ret = regulator_set_voltage_tol(dvdd_cpu_reg, volt, 0); + if (ret) + dev_err(cpu_dev, "failed to scale dvdd_cpu down: %d\n", ret); + } + + val = readl(ap_sys_reg); + if (re_modify_bus_freq) { + val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; + val |= LIGHT_C910_BUS_CLK_DIV_RATIO_2; + + writel(val, ap_sys_reg); + val &= ~LIGHT_C910_BUS_CLK_SYNC; + writel(val, ap_sys_reg); + udelay(1); + val |= LIGHT_C910_BUS_CLK_SYNC; + writel(val, ap_sys_reg); + udelay(1); + } + + mutex_unlock(&cpufreq_lock); + + return 0; +} + +static int light_cpufreq_init(struct cpufreq_policy *policy) +{ + policy->clk = clks[LIGHT_C910_CCLK].clk; + policy->cur = clk_get_rate(policy->clk) / 1000; + cpufreq_generic_init(policy, freq_table, transition_latency); + policy->suspend_freq = max_freq; + dev_pm_opp_of_register_em(cpu_dev, policy->cpus); + + return 0; +} + +static int light_cpufreq_reboot_notifier(struct notifier_block *this, + unsigned long event, void *ptr) +{ + mutex_lock(&cpufreq_lock); + cpufreq_denied = true; + mutex_unlock(&cpufreq_lock); + + return NOTIFY_DONE; +} + +static struct notifier_block cpufreq_reboot_notifier = { + .notifier_call = light_cpufreq_reboot_notifier, +}; + +static struct cpufreq_driver light_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | + CPUFREQ_IS_COOLING_DEV, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = light_set_target, + .get = cpufreq_generic_get, + .init = light_cpufreq_init, + .name = "light-cpufreq", + .attr = cpufreq_generic_attr, + .suspend = cpufreq_generic_suspend, +}; + +static int light_cpufreq_pm_notify(struct notifier_block *nb, + unsigned long event, void *dummy) +{ + switch (event) { + case PM_SUSPEND_PREPARE: + /* TBD */ + break; + case PM_POST_SUSPEND: + /* TBD */ + break; + default: + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block light_cpufreq_pm_notifier = { + .notifier_call = light_cpufreq_pm_notify, +}; + +/* + * Set CPU PLL1's frequency as minimum on panic + */ +static int panic_cpufreq_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + int cpu = smp_processor_id(); + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + u32 val = readl(ap_sys_reg); + + pr_info("enter panic_cpufreq_notifier_call\n"); + + /* + * set CPU PLL1's frequency as minimum to compatible voltage + * becarefull if the PLL1 is serving the cpu core, swith to PLL0 first + */ + if (strcmp(__clk_get_name(clk_get_parent(clks[LIGHT_C910_CCLK].clk)), + __clk_get_name(clks[LIGHT_C910_CCLK_I0].clk))) { + pr_debug("[%s,%d]\n", __func__, __LINE__); + clk_prepare_enable(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk, policy->min * 1000); + udelay(1); + clk_set_parent(clks[LIGHT_C910_CCLK].clk, clks[LIGHT_C910_CCLK_I0].clk); + + pr_debug("[%s,%d]\n", __func__, __LINE__); + } + + pr_debug("[%s,%d]\n", __func__, __LINE__); + /* + * since the clk driver will use PLL1 as the default clock source, + * in order to compatible voltage which is unpredictable we should + * set the CPU PLL1's frequency as minimum in advance, otherwise the + * system may crash in crash kernel stage. + */ + clk_prepare_enable(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk, policy->min * 1000); + udelay(1); + + pr_info("finish to execute cpufreq notifier callback on panic\n"); + + return 0; +} + +static struct notifier_block panic_cpufreq_notifier = { + .notifier_call = panic_cpufreq_notifier_call, +}; + +static int light_cpufreq_probe(struct platform_device *pdev) +{ + struct device_node *np; + int num, ret; + const struct property *prop; + const __be32 *val; + u32 nr, i, j; + + np = of_find_compatible_node(NULL, NULL, "thead,light_sys_reg"); + if (!np) + return -ENOENT; + ap_sys_reg = of_iomap(np, 0); + WARN_ON(!ap_sys_reg); + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) { + pr_err("failed to get cpu0 device\n"); + return -ENODEV; + } + + np = of_node_get(cpu_dev->of_node); + if (!np) { + dev_err(cpu_dev, "failed to find cpu0 node\n"); + return -ENOENT; + } + + num_clks = LIGHT_MPW_CPUFREQ_CLK_NUM; + ret = clk_bulk_get(cpu_dev, num_clks, clks); + if (ret) + goto put_node; + + dvdd_cpu_reg = regulator_get(cpu_dev, "dvdd"); + dvddm_cpu_reg = regulator_get(cpu_dev, "dvddm"); + if (PTR_ERR(dvdd_cpu_reg) == -EPROBE_DEFER || + PTR_ERR(dvddm_cpu_reg) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + dev_dbg(cpu_dev, "regulators not ready, defer\n"); + goto put_reg; + } + + if (IS_ERR(dvdd_cpu_reg) || IS_ERR(dvddm_cpu_reg)) { + dev_err(cpu_dev, "failed to get regulators\n"); + ret = -ENOENT; + goto put_reg; + } + + ret = dev_pm_opp_of_add_table(cpu_dev); + if (ret < 0) { + dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); + goto put_reg; + } + + num = dev_pm_opp_get_opp_count(cpu_dev); + if (num < 0) { + ret = num; + dev_err(cpu_dev, "no OPP table is found: %d\n", ret); + goto out_free_opp; + } + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto out_free_opp; + } + + /* Make light_dvddm_volt array's size same as dvdd opp number */ + light_dvddm_volt = devm_kcalloc(cpu_dev, num, sizeof(*light_dvddm_volt), + GFP_KERNEL); + if (light_dvddm_volt == NULL) { + ret = -ENOMEM; + goto free_freq_table; + } + + if (of_get_property(np, "dvfs_sv", NULL)) + light_dvfs_sv = true; + else + light_dvfs_sv = false; + + prop = of_find_property(np, "light,dvddm-operating-points", NULL); + if (!prop || !prop->value) + goto soc_opp_out; + + nr = prop->length / sizeof(u32); + if (nr % 2 || (nr / 2) < num) + goto soc_opp_out; + + for (j = 0; j < num; j++) { + val = prop->value; + for (i = 0; i < nr / 2; i++) { + unsigned long freq = be32_to_cpup(val++); + unsigned long volt = be32_to_cpup(val++); + if (freq_table[j].frequency == freq) { + light_dvddm_volt[soc_opp_count++] = volt; + break; + } + } + } + +soc_opp_out: + if (soc_opp_count != num) + dev_warn(cpu_dev, "Not find valid light,dvddm-operating-points property\n"); + + if (of_property_read_u32(np, "clock-latency", &transition_latency)) + transition_latency = CPUFREQ_ETERNAL; + + max_freq = freq_table[--num].frequency; + + ret = cpufreq_register_driver(&light_cpufreq_driver); + if (ret) { + dev_err(cpu_dev, "failed register driver: %d\n", ret); + goto free_freq_table; + } + + register_pm_notifier(&light_cpufreq_pm_notifier); + + of_node_put(np); + + ret = atomic_notifier_chain_register(&panic_notifier_list, + &panic_cpufreq_notifier); + if (ret) { + pr_err("unable to register notifier(%d)\n", ret); + goto free_freq_table; + } + + register_reboot_notifier(&cpufreq_reboot_notifier); + + dev_info(cpu_dev, "finish to register cpufreq driver\n"); + + return 0; + +free_freq_table: + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); +out_free_opp: + dev_pm_opp_of_remove_table(cpu_dev); +put_reg: + if (!IS_ERR(dvdd_cpu_reg)) + regulator_put(dvdd_cpu_reg); + if (!IS_ERR(dvddm_cpu_reg)) + regulator_put(dvddm_cpu_reg); + + clk_bulk_put(num_clks, clks); +put_node: + of_node_put(np); + + return ret; +} + +static int light_cpufreq_remove(struct platform_device *pdev) +{ + cpufreq_unregister_driver(&light_cpufreq_driver); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); + dev_pm_opp_of_remove_table(cpu_dev); + regulator_put(dvdd_cpu_reg); + regulator_put(dvddm_cpu_reg); + + clk_bulk_put(num_clks, clks); + + return 0; +} + +static const struct of_device_id light_cpufreq_match[] = { + { .compatible = "thead,light-mpw-cpufreq" }, + {}, +}; + +static struct platform_driver light_cpufreq_platdrv = { + .driver = { + .name = "thead,light-mpw-cpufreq", + .of_match_table = light_cpufreq_match, + }, + .probe = light_cpufreq_probe, + .remove = light_cpufreq_remove, +}; +module_platform_driver(light_cpufreq_platdrv); + +MODULE_ALIAS("platform:light-cpufreq"); +MODULE_AUTHOR("fugang.duan "); +MODULE_DESCRIPTION("Thead Light cpufreq driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b59e3041fd6275..3d091439c28da5 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -314,5 +314,6 @@ source "drivers/firmware/psci/Kconfig" source "drivers/firmware/smccc/Kconfig" source "drivers/firmware/tegra/Kconfig" source "drivers/firmware/xilinx/Kconfig" +source "drivers/firmware/thead/Kconfig" endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 28fcddcd688fc2..a817fe549c9fd1 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -38,3 +38,4 @@ obj-y += psci/ obj-y += smccc/ obj-y += tegra/ obj-y += xilinx/ +obj-y += thead/ diff --git a/drivers/firmware/thead/Kconfig b/drivers/firmware/thead/Kconfig new file mode 100644 index 00000000000000..ad5b82dd51e8e5 --- /dev/null +++ b/drivers/firmware/thead/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +config LIGHT_AON + bool "Thead Light Aon Protocol driver" + depends on THEAD_LIGHT_MBOX + default y + help + Thead light Aon is a low-level system function which runs a dedicated + thead riscv E902 core to provide power, clock and resource management. + + This driver manages the IPC interface between host cpu liks thead + and the Aon firmware running on thead riscv E902 core. + +config LIGHT_AON_PD + bool "Thead Light Aon Power Domain driver" + depends on LIGHT_AON + select PM_GENERIC_DOMAINS if PM + help + The Aon power domain virtual driver. diff --git a/drivers/firmware/thead/Makefile b/drivers/firmware/thead/Makefile new file mode 100644 index 00000000000000..6bd2afe817ef4a --- /dev/null +++ b/drivers/firmware/thead/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_LIGHT_AON) += light_aon.o light_aon_misc.o light_aon_test.o +obj-$(CONFIG_LIGHT_AON_PD) += light_aon_pd.o diff --git a/drivers/firmware/thead/light_aon.c b/drivers/firmware/thead/light_aon.c new file mode 100644 index 00000000000000..8fbd808d73be0a --- /dev/null +++ b/drivers/firmware/thead/light_aon.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_RX_TIMEOUT (msecs_to_jiffies(300)) +#define MAX_TX_TIMEOUT (msecs_to_jiffies(500)) + +struct light_aon_chan { + struct light_aon_ipc *aon_ipc; + + struct mbox_client cl; + struct mbox_chan *ch; + struct completion tx_done; +}; + +struct light_aon_ipc { + struct light_aon_chan chans; + struct device *dev; + struct mutex lock; + struct completion done; + u32 *msg; +}; + +/* + * This type is used to indicate error response for most functions. + */ +enum light_aon_error_codes { + LIGHT_AON_ERR_NONE = 0, /* Success */ + LIGHT_AON_ERR_VERSION = 1, /* Incompatible API version */ + LIGHT_AON_ERR_CONFIG = 2, /* Configuration error */ + LIGHT_AON_ERR_PARM = 3, /* Bad parameter */ + LIGHT_AON_ERR_NOACCESS = 4, /* Permission error (no access) */ + LIGHT_AON_ERR_LOCKED = 5, /* Permission error (locked) */ + LIGHT_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ + LIGHT_AON_ERR_NOTFOUND = 7, /* Not found */ + LIGHT_AON_ERR_NOPOWER = 8, /* No power */ + LIGHT_AON_ERR_IPC = 9, /* Generic IPC error */ + LIGHT_AON_ERR_BUSY = 10, /* Resource is currently busy/active */ + LIGHT_AON_ERR_FAIL = 11, /* General I/O failure */ + LIGHT_AON_ERR_LAST +}; + +static int light_aon_linux_errmap[LIGHT_AON_ERR_LAST] = { + 0, /* LIGHT_AON_ERR_NONE */ + -EINVAL, /* LIGHT_AON_ERR_VERSION */ + -EINVAL, /* LIGHT_AON_ERR_CONFIG */ + -EINVAL, /* LIGHT_AON_ERR_PARM */ + -EACCES, /* LIGHT_AON_ERR_NOACCESS */ + -EACCES, /* LIGHT_AON_ERR_LOCKED */ + -ERANGE, /* LIGHT_AON_ERR_UNAVAILABLE */ + -EEXIST, /* LIGHT_AON_ERR_NOTFOUND */ + -EPERM, /* LIGHT_AON_ERR_NOPOWER */ + -EPIPE, /* LIGHT_AON_ERR_IPC */ + -EBUSY, /* LIGHT_AON_ERR_BUSY */ + -EIO, /* LIGHT_AON_ERR_FAIL */ +}; + +static struct light_aon_ipc *light_aon_ipc_handle; + +static inline int light_aon_to_linux_errno(int errno) +{ + if (errno >= LIGHT_AON_ERR_NONE && errno < LIGHT_AON_ERR_LAST) + return light_aon_linux_errmap[errno]; + return -EIO; +} + +/* + * Get the default handle used by SCU + */ +int light_aon_get_handle(struct light_aon_ipc **ipc) +{ + if (!light_aon_ipc_handle) + return -EPROBE_DEFER; + + *ipc = light_aon_ipc_handle; + return 0; +} +EXPORT_SYMBOL(light_aon_get_handle); + +static void light_aon_tx_done(struct mbox_client *cl, void *mssg, int r) +{ + struct light_aon_chan *aon_chan = container_of(cl, struct light_aon_chan, cl); + + complete(&aon_chan->tx_done); +} + +static void light_aon_rx_callback(struct mbox_client *c, void *msg) +{ + struct light_aon_chan *aon_chan = container_of(c, struct light_aon_chan, cl); + struct light_aon_ipc *aon_ipc = aon_chan->aon_ipc; + + memcpy(aon_ipc->msg, msg, LIGHT_AON_RPC_MSG_NUM * sizeof(u32)); + dev_dbg(aon_ipc->dev, "msg head: 0x%x\n", *((u32 *)msg)); + complete(&aon_ipc->done); +} + +static int light_aon_ipc_write(struct light_aon_ipc *aon_ipc, void *msg) +{ + struct light_aon_rpc_msg_hdr *hdr = msg; + struct light_aon_chan *aon_chan; + u32 *data = msg; + int ret; + + /* check size, currently it requires 7 MSG in one transfer */ + if (hdr->size != LIGHT_AON_RPC_MSG_NUM) + return -EINVAL; + + dev_dbg(aon_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc, + hdr->func, hdr->size); + + aon_chan = &aon_ipc->chans; + + if (!wait_for_completion_timeout(&aon_chan->tx_done, + MAX_TX_TIMEOUT)) { + dev_err(aon_ipc->dev, "tx_done timeout\n"); + return -ETIMEDOUT; + } + reinit_completion(&aon_chan->tx_done); + + ret = mbox_send_message(aon_chan->ch, data); + if (ret < 0) + return ret; + + return 0; +} + +/* + * RPC command/response + */ +int light_aon_call_rpc(struct light_aon_ipc *aon_ipc, void *msg, bool have_resp) +{ + struct light_aon_rpc_msg_hdr *hdr; + int ret; + + if (WARN_ON(!aon_ipc || !msg)) + return -EINVAL; + + mutex_lock(&aon_ipc->lock); + reinit_completion(&aon_ipc->done); + + if (have_resp) + aon_ipc->msg = msg; + + ret = light_aon_ipc_write(aon_ipc, msg); + if (ret < 0) { + dev_err(aon_ipc->dev, "RPC send msg failed: %d\n", ret); + goto out; + } + + if (have_resp) { + if (!wait_for_completion_timeout(&aon_ipc->done, + MAX_RX_TIMEOUT)) { + dev_err(aon_ipc->dev, "RPC send msg timeout\n"); + mutex_unlock(&aon_ipc->lock); + return -ETIMEDOUT; + } + + /* response status is stored in hdr->func field */ + hdr = msg; + ret = hdr->func; + } + +out: + mutex_unlock(&aon_ipc->lock); + + dev_dbg(aon_ipc->dev, "RPC SVC done\n"); + + return light_aon_to_linux_errno(ret); +} +EXPORT_SYMBOL(light_aon_call_rpc); + +static int light_aon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct light_aon_ipc *aon_ipc; + struct light_aon_chan *aon_chan; + struct mbox_client *cl; + int ret; + + aon_ipc = devm_kzalloc(dev, sizeof(*aon_ipc), GFP_KERNEL); + if (!aon_ipc) + return -ENOMEM; + + aon_chan = &aon_ipc->chans; + cl = &aon_chan->cl; + cl->dev = dev; + cl->tx_block = false; + cl->knows_txdone = true; + cl->rx_callback = light_aon_rx_callback; + + /* Initial tx_done completion as "done" */ + cl->tx_done = light_aon_tx_done; + init_completion(&aon_chan->tx_done); + complete(&aon_chan->tx_done); + + aon_chan->aon_ipc = aon_ipc; + aon_chan->ch = mbox_request_channel_byname(cl, "aon"); + if (IS_ERR(aon_chan->ch)) { + ret = PTR_ERR(aon_chan->ch); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to request aon mbox chan ret %d\n", ret); + return ret; + } + + dev_dbg(dev, "request thead mbox chan: aon\n"); + + aon_ipc->dev = dev; + mutex_init(&aon_ipc->lock); + init_completion(&aon_ipc->done); + + light_aon_ipc_handle = aon_ipc; + + return devm_of_platform_populate(dev); +} + +static const struct of_device_id light_aon_match[] = { + { .compatible = "thead,light-aon", }, + { /* Sentinel */ } +}; + +static struct platform_driver light_aon_driver = { + .driver = { + .name = "light-aon", + .of_match_table = light_aon_match, + }, + .probe = light_aon_probe, +}; +builtin_platform_driver(light_aon_driver); + +MODULE_AUTHOR("fugang.duan "); +MODULE_DESCRIPTION("Thead Light firmware protocol driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/thead/light_aon_misc.c b/drivers/firmware/thead/light_aon_misc.c new file mode 100644 index 00000000000000..3fb689f4b2615f --- /dev/null +++ b/drivers/firmware/thead/light_aon_misc.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include + +struct light_aon_msg_req_misc_set_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 ctrl; + u32 val; + u16 resource; + u16 reserved[7]; +} __packed __aligned(4); + +struct light_aon_msg_req_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 ctrl; + u16 resource; + u16 reserved[9]; +} __packed __aligned(4); + +struct light_aon_msg_resp_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 val; + u32 reserved[5]; +} __packed __aligned(4); + +int light_aon_misc_set_control(struct light_aon_ipc *ipc, u16 resource, + u32 ctrl, u32 val) +{ + struct light_aon_msg_req_misc_set_ctrl msg; + struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; + + hdr->ver = LIGHT_AON_RPC_VERSION; + hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; + hdr->func = (uint8_t)LIGHT_AON_MISC_FUNC_SET_CONTROL; + hdr->size = LIGHT_AON_RPC_MSG_NUM; + + msg.ctrl = ctrl; + msg.val = val; + msg.resource = resource; + + return light_aon_call_rpc(ipc, &msg, true); +} +EXPORT_SYMBOL(light_aon_misc_set_control); + +int light_aon_misc_get_control(struct light_aon_ipc *ipc, u16 resource, + u32 ctrl, u32 *val) +{ + struct light_aon_msg_req_misc_get_ctrl msg; + struct light_aon_msg_resp_misc_get_ctrl *resp; + struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; + int ret; + + hdr->ver = LIGHT_AON_RPC_VERSION; + hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; + hdr->func = (uint8_t)LIGHT_AON_MISC_FUNC_GET_CONTROL; + hdr->size = LIGHT_AON_RPC_MSG_NUM; + + msg.ctrl = ctrl; + msg.resource = resource; + + ret = light_aon_call_rpc(ipc, &msg, true); + if (ret) + return ret; + + resp = (struct light_aon_msg_resp_misc_get_ctrl *)&msg; + if (val != NULL) + *val = resp->val; + + return 0; +} +EXPORT_SYMBOL(light_aon_misc_get_control); diff --git a/drivers/firmware/thead/light_aon_pd.c b/drivers/firmware/thead/light_aon_pd.c new file mode 100644 index 00000000000000..3bef67df5a0a3e --- /dev/null +++ b/drivers/firmware/thead/light_aon_pd.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct light_aon_msg_req_set_resource_power_mode { + struct light_aon_rpc_msg_hdr hdr; + u16 resource; + u16 mode; + u16 reserved[10]; +} __packed __aligned(4); + +#define LIGHT_AONU_PD_NAME_SIZE 20 +#define LIGHT_AONU_PD_STATE_NAME_SIZE 10 + +struct light_aon_pm_domain { + struct generic_pm_domain pd; + char name[LIGHT_AONU_PD_NAME_SIZE]; + u16 rsrc; +}; + +struct light_aon_pd_range { + char *name; + u32 rsrc; + u8 num; + + /* add domain index */ + bool postfix; + u8 start_from; +}; + +struct light_aon_pd_soc { + const struct light_aon_pd_range *pd_ranges; + u8 num_ranges; +}; + +static const struct light_aon_pd_range light_aon_pd_ranges[] = { + /* AUDIO SS */ + { "audio", LIGHT_AON_AUDIO_PD, 1, false, 0 }, + { "vdec", LIGHT_AON_VDEC_PD, 1, false, 0}, + { "npu", LIGHT_AON_NPU_PD, 1, false, 0}, + { "venc", LIGHT_AON_VENC_PD, 1, false, 0}, + { "gpu", LIGHT_AON_GPU_PD, 1, false, 0}, + { "dsp0", LIGHT_AON_DSP0_PD, 1, false, 0}, + { "dsp1", LIGHT_AON_DSP1_PD, 1, false, 0}, + {}, +}; + +static const struct light_aon_pd_soc light_aon_pd = { + .pd_ranges = light_aon_pd_ranges, + .num_ranges = ARRAY_SIZE(light_aon_pd_ranges), +}; + +static struct light_aon_ipc *pm_ipc_handle; +static struct dentry *pd_debugfs_root; +struct dentry *pd_pde; +struct genpd_onecell_data *genpd_data; + +static inline struct light_aon_pm_domain *to_light_aon_pd(struct generic_pm_domain *genpd) +{ + return container_of(genpd, struct light_aon_pm_domain, pd); +} + +static int light_aon_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct light_aon_msg_req_set_resource_power_mode msg; + struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; + struct light_aon_pm_domain *pd; + int ret; + + pd = to_light_aon_pd(domain); + + hdr->ver = LIGHT_AON_RPC_VERSION; + hdr->svc = LIGHT_AON_RPC_SVC_PM; + hdr->func = LIGHT_AON_PM_FUNC_SET_RESOURCE_POWER_MODE; + hdr->size = LIGHT_AON_RPC_MSG_NUM; + + msg.resource = pd->rsrc; + msg.mode = power_on ? LIGHT_AON_PM_PW_MODE_ON : LIGHT_AON_PM_PW_MODE_OFF; + + ret = light_aon_call_rpc(pm_ipc_handle, &msg, true); + if (ret) + dev_err(&domain->dev, "failed to power %s resource %d ret %d\n", + power_on ? "up" : "off", pd->rsrc, ret); + + return ret; +} + +static int light_aon_pd_power_on(struct generic_pm_domain *domain) +{ + return light_aon_pd_power(domain, true); +} + +static int light_aon_pd_power_off(struct generic_pm_domain *domain) +{ + return light_aon_pd_power(domain, false); +} + +static struct generic_pm_domain *light_aon_pd_xlate(struct of_phandle_args *spec, + void *data) +{ + struct generic_pm_domain *domain = ERR_PTR(-ENOENT); + struct genpd_onecell_data *pd_data = data; + unsigned int i; + + for (i = 0; i < pd_data->num_domains; i++) { + struct light_aon_pm_domain *aon_pd; + + aon_pd = to_light_aon_pd(pd_data->domains[i]); + if (aon_pd->rsrc == spec->args[0]) { + domain = &aon_pd->pd; + break; + } + } + + return domain; +} + +static struct light_aon_pm_domain * +light_aon_add_pm_domain(struct device *dev, int idx, + const struct light_aon_pd_range *pd_ranges) +{ + struct light_aon_pm_domain *aon_pd; + int ret; + + aon_pd = devm_kzalloc(dev, sizeof(*aon_pd), GFP_KERNEL); + if (!aon_pd) + return ERR_PTR(-ENOMEM); + + aon_pd->rsrc = pd_ranges->rsrc + idx; + aon_pd->pd.power_off = light_aon_pd_power_off; + aon_pd->pd.power_on = light_aon_pd_power_on; + + if (pd_ranges->postfix) + snprintf(aon_pd->name, sizeof(aon_pd->name), + "%s%i", pd_ranges->name, pd_ranges->start_from + idx); + else + snprintf(aon_pd->name, sizeof(aon_pd->name), + "%s", pd_ranges->name); + + aon_pd->pd.name = aon_pd->name; + +#if 0 + if (aon_pd->rsrc >= LIGHT_AON_R_LAST) { + dev_warn(dev, "invalid pd %s rsrc id %d found", + aon_pd->name, aon_pd->rsrc); + + devm_kfree(dev, aon_pd); + return NULL; + } +#endif + + ret = pm_genpd_init(&aon_pd->pd, NULL, true); + if (ret) { + dev_warn(dev, "failed to init pd %s rsrc id %d", + aon_pd->name, aon_pd->rsrc); + devm_kfree(dev, aon_pd); + return NULL; + } + + return aon_pd; +} + +static int light_aon_init_pm_domains(struct device *dev, + const struct light_aon_pd_soc *pd_soc) +{ + const struct light_aon_pd_range *pd_ranges = pd_soc->pd_ranges; + struct generic_pm_domain **domains; + struct genpd_onecell_data *pd_data; + struct light_aon_pm_domain *aon_pd; + u32 count = 0; + int i, j; + + for (i = 0; i < pd_soc->num_ranges; i++) + count += pd_ranges[i].num; + + domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL); + if (!domains) + return -ENOMEM; + + pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL); + if (!pd_data) + return -ENOMEM; + + count = 0; + for (i = 0; i < pd_soc->num_ranges; i++) { + for (j = 0; j < pd_ranges[i].num; j++) { + aon_pd = light_aon_add_pm_domain(dev, j, &pd_ranges[i]); + if (IS_ERR_OR_NULL(aon_pd)) + continue; + + domains[count++] = &aon_pd->pd; + dev_dbg(dev, "added power domain %s\n", aon_pd->pd.name); + } + } + + pd_data->domains = domains; + pd_data->num_domains = count; + pd_data->xlate = light_aon_pd_xlate; + genpd_data = pd_data; + + of_genpd_add_provider_onecell(dev->of_node, pd_data); + + return 0; +} + +static char *pd_get_user_string(const char __user *userbuf, size_t userlen) +{ + char *buffer; + + buffer = vmalloc(userlen + 1); + if (!buffer) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(buffer, userbuf, userlen) != 0) { + vfree(buffer); + return ERR_PTR(-EFAULT); + } + + /* got the string, now strip linefeed. */ + if (buffer[userlen - 1] == '\n') + buffer[userlen -1] = '\0'; + else + buffer[userlen] = '\0'; + + pr_debug("buffer = %s\n", buffer); + + return buffer; +} + +static ssize_t light_power_domain_write(struct file *file, + const char __user *userbuf, + size_t userlen, loff_t *ppos) +{ + char *buffer, *start, *end; + struct seq_file *m = (struct seq_file *)file->private_data; + struct genpd_onecell_data *aon_pds_data = m->private; + struct generic_pm_domain *hitted_pm_genpd; + char pd_name[LIGHT_AONU_PD_NAME_SIZE]; + char pd_state[LIGHT_AONU_PD_STATE_NAME_SIZE]; + int idx, ret; + size_t origin_len = userlen; + + buffer = pd_get_user_string(userbuf, userlen); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + start = skip_spaces(buffer); + end = start; + while(!isspace(*end) && *end != '\0') + end++; + + *end = '\0'; + strcpy(pd_name, start); + pr_debug("power domain name: %s\n", pd_name); + + /* find the target power domain */ + for (idx = 0; idx < aon_pds_data->num_domains; idx++) { + struct generic_pm_domain *domain = aon_pds_data->domains[idx]; + pr_debug("generic pm domain name: %s, pd_name: %s, ret = %d\n", + domain->name, pd_name, strcmp(pd_name, domain->name)); + if (strcmp(pd_name, domain->name)) + continue; + else { + hitted_pm_genpd = aon_pds_data->domains[idx]; + pr_debug("target pm power domain-%s found, index: %d\n", + hitted_pm_genpd->name, idx); + break; + } + } + + if (idx >= aon_pds_data->num_domains) { + pr_err("no taget power domain-%s found, idx = %d, total pd numbers = %d\n", + pd_name, idx, aon_pds_data->num_domains); + userlen = -EINVAL; + goto out; + } + + if (!hitted_pm_genpd->power_on && !hitted_pm_genpd->power_off) { + pr_err("no power operations registered for power domain-%s\n", pd_name); + userlen = -EINVAL; + goto out; + } + + end = end + 1; + start = skip_spaces(end); + end = start; + while(!isspace(*end) && *end != '\0') + end++; + + *end = '\0'; + strcpy(pd_state, start); + pr_debug("power domain target state: %s\n", pd_state); + + if (!strcmp(pd_state, "on")) { + ret = hitted_pm_genpd->power_on(hitted_pm_genpd); + if (ret) { + userlen = ret; + goto out; + } + } else if (!strcmp(pd_state, "off")) { + ret = hitted_pm_genpd->power_off(hitted_pm_genpd); + if (ret) { + userlen = ret; + goto out; + } + } else { + pr_err("invalid power domain target state, not 'on' or 'off'\n"); + userlen = -EINVAL; + goto out; + } + +out: + memset(buffer, 0, origin_len); + vfree(buffer); + + return userlen; +} + +static int light_power_domain_show(struct seq_file *m, void *v) +{ + struct genpd_onecell_data *pd_data = m->private; + u32 count = pd_data->num_domains; + int idx; + + seq_puts(m, "[Power domain name list]: "); + for(idx = 0; idx < count; idx++) + seq_printf(m, "%s ", pd_data->domains[idx]->name); + seq_printf(m, "\n"); + seq_puts(m, "[Power on domain usage]: echo power_name on > domain\n"); + seq_puts(m, "[Power off domain usage]: echo power_name off > domain\n"); + + return 0; +} + +static int light_power_domain_open(struct inode *inode, struct file *file) +{ + struct genpd_onecell_data *pd_data = inode->i_private; + + return single_open(file, light_power_domain_show, pd_data); +} + +static const struct file_operations light_power_domain_fops = { + .owner = THIS_MODULE, + .write = light_power_domain_write, + .read = seq_read, + .open = light_power_domain_open, + .llseek = generic_file_llseek, +}; + +static void pd_debugfs_init(struct genpd_onecell_data *aon_pds_data) +{ + umode_t mode = S_IRUSR | S_IWUSR | S_IFREG; + + pd_debugfs_root = debugfs_create_dir("power_domain", NULL); + if (!pd_debugfs_root || IS_ERR(pd_debugfs_root)) + return; + + pd_pde = debugfs_create_file("domain", mode, pd_debugfs_root, (void *)aon_pds_data, &light_power_domain_fops); + + pr_info("succeed to create power domain debugfs direntry\n"); +} + +static int light_aon_pd_probe(struct platform_device *pdev) +{ + const struct light_aon_pd_soc *pd_soc; + int ret; + + ret = light_aon_get_handle(&pm_ipc_handle); + if (ret) + return ret; + + pd_soc = of_device_get_match_data(&pdev->dev); + if (!pd_soc) + return -ENODEV; + + ret = light_aon_init_pm_domains(&pdev->dev, pd_soc); + if (ret) + return ret; + + pd_debugfs_init(genpd_data); + + return 0; +} + +static const struct of_device_id light_aon_pd_match[] = { + { .compatible = "thead,light-aon-pd", &light_aon_pd}, + { /* sentinel */ } +}; + +static struct platform_driver light_aon_pd_driver = { + .driver = { + .name = "light-aon-pd", + .of_match_table = light_aon_pd_match, + }, + .probe = light_aon_pd_probe, +}; +builtin_platform_driver(light_aon_pd_driver); + +MODULE_AUTHOR("fugang.duan "); +MODULE_DESCRIPTION("Thead Light firmware protocol driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/thead/light_aon_test.c b/drivers/firmware/thead/light_aon_test.c new file mode 100644 index 00000000000000..172025430853c1 --- /dev/null +++ b/drivers/firmware/thead/light_aon_test.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MBOX_MAX_MSG_LEN 28 + +static struct dentry *root_debugfs_dir; + +struct light_aon_msg_req_misc_set_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 ctrl; + u32 val; + u16 resource; + u16 reserved[7]; +} __packed __aligned(4); + +struct light_aon_msg_req_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 ctrl; + u16 resource; + u16 reserved[9]; +} __packed __aligned(4); + +struct light_aon_msg_resp_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 val; + u32 reserved[5]; +} __packed __aligned(4); + +struct light_aon_device { + struct device *dev; + char *test_buf; + struct light_aon_ipc *ipc_handle; +}; + +static ssize_t light_aon_test_buf_write(struct file *filp, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct light_aon_device *tdev = filp->private_data; + int ret; + + if (count > MBOX_MAX_MSG_LEN) + count = MBOX_MAX_MSG_LEN; + + ret = copy_from_user(tdev->test_buf, userbuf, count); + if (ret) { + ret = -EFAULT; + goto out; + } + + ret = light_aon_misc_set_control(tdev->ipc_handle, 0x1, 0x2, 0x3); + ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x11, 0x12, 0x13); + ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x21, 0x22, 0x23); + ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x31, 0x32, 0x33); + if (ret) + dev_err(tdev->dev, "failed to set control\n"); + + //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->test_buf, MBOX_MAX_MSG_LEN, true); + +out: + return ret < 0 ? ret : count; +} + +static ssize_t light_aon_test_buf_read(struct file *filp, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct light_aon_device *tdev = filp->private_data; + + //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->test_buf, MBOX_MAX_MSG_LEN, true); + memset(tdev->test_buf, 0, MBOX_MAX_MSG_LEN); + + return MBOX_MAX_MSG_LEN; +} + +static const struct file_operations light_aon_test_buf_ops = { + .write = light_aon_test_buf_write, + .read = light_aon_test_buf_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static int light_aon_add_debugfs(struct platform_device *pdev, struct light_aon_device *tdev) +{ + root_debugfs_dir = debugfs_create_dir("light_aon",NULL); + if (!root_debugfs_dir) { + dev_err(&pdev->dev, "Failed to create light_aon_test debugfs\n"); + return -EINVAL; + } + + debugfs_create_file("test", 0600, root_debugfs_dir, tdev, &light_aon_test_buf_ops); + return 0; +} + +static int light_aon_probe(struct platform_device *pdev) +{ + struct light_aon_device *tdev; + int ret; + + tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); + if (!tdev) + return -ENOMEM; + + tdev->dev = &pdev->dev; + platform_set_drvdata(pdev, tdev); + + tdev->test_buf = devm_kzalloc(&pdev->dev, MBOX_MAX_MSG_LEN, GFP_KERNEL); + if (!tdev->test_buf) + return -ENOMEM; + + ret = light_aon_get_handle(&(tdev->ipc_handle)); + if (ret) { + dev_err(&pdev->dev, "failed to get ipc_handle\n"); + return ret; + } + + ret = light_aon_add_debugfs(pdev, tdev); + if (ret) + return ret; + + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +} + +static int light_aon_remove(struct platform_device *pdev) +{ + debugfs_remove_recursive(root_debugfs_dir); + return 0; +} + +static const struct of_device_id light_aon_match[] = { + { .compatible = "thead,light-aon-test" }, + {}, +}; + +static struct platform_driver light_aon_driver = { + .driver = { + .name = "thead,light-aon-test", + .of_match_table = light_aon_match, + }, + .probe = light_aon_probe, + .remove = light_aon_remove, +}; +module_platform_driver(light_aon_driver); + +MODULE_AUTHOR("fugang.duan "); +MODULE_DESCRIPTION("Thead Light firmware protocol test driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index bc2e265cb02d2a..ca9cfa3ac9f7dd 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -295,4 +295,12 @@ config QCOM_IPCC acts as an interrupt controller for receiving interrupts from clients. Say Y here if you want to build this driver. +config THEAD_LIGHT_MBOX + bool "Thead light Mailbox" + depends on ARCH_THEAD || COMPILE_TEST + default y + help + Mailbox implementation for Thead light SoCs. + + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index fc93761171113e..7e82b9edccd444 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -62,3 +62,6 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o + +obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox.o +#obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox-client.o diff --git a/drivers/mailbox/light-mailbox-client.c b/drivers/mailbox/light-mailbox-client.c new file mode 100644 index 00000000000000..10cf7ae15cbc46 --- /dev/null +++ b/drivers/mailbox/light-mailbox-client.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MBOX_MAX_MSG_LEN 28 +#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28 +#define HEXDUMP_BYTES_PER_LINE 28 +#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2) +#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE)) + +static struct dentry *root_debugfs_dir; + +struct mbox_client_light_device { + struct device *dev; + void __iomem *tx_mmio; + void __iomem *rx_mmio; + struct mbox_chan *tx_channel; + struct mbox_chan *rx_channel; + char *rx_buffer; + char *message; + spinlock_t lock; +}; + +static ssize_t mbox_client_light_message_write(struct file *filp, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct mbox_client_light_device *tdev = filp->private_data; + void *data; + int ret; + + if (!tdev->tx_channel) { + dev_err(tdev->dev, "Channel cannot do Tx\n"); + return -EINVAL; + } + + if (count > WJ_MBOX_SEND_MAX_MESSAGE_LENGTH) + count = WJ_MBOX_SEND_MAX_MESSAGE_LENGTH; + + tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); + if (!tdev->message) + return -ENOMEM; + + ret = copy_from_user(tdev->message, userbuf, count); + if (ret) { + ret = -EFAULT; + goto out; + } + + data = tdev->message; + print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->message, MBOX_MAX_MSG_LEN, true); + + ret = mbox_send_message(tdev->tx_channel, data); + if (ret < 0) + dev_err(tdev->dev, "Failed to send message via mailbox\n"); + +out: + kfree(tdev->message); + return ret < 0 ? ret : count; +} + +static ssize_t mbox_client_light_message_read(struct file *filp, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct mbox_client_light_device *tdev = filp->private_data; + unsigned long flags; + + print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); + spin_lock_irqsave(&tdev->lock, flags); + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); + spin_unlock_irqrestore(&tdev->lock, flags); + + return MBOX_MAX_MSG_LEN; +} + +static const struct file_operations mbox_client_light_message_ops = { + .write = mbox_client_light_message_write, + .read = mbox_client_light_message_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static int index_names = 0; +static bool debugfs_dir_created = false; +static const char* file_names[] = {"mbox-client0", "mbox-client1"}; + +static int mbox_client_light_add_debugfs(struct platform_device *pdev, + struct mbox_client_light_device *tdev) +{ + if (!debugfs_initialized()) + return 0; + + if (index_names > 2) { + dev_err(&pdev->dev, "Max device index is 2\n"); + return 0; + } + + if (!debugfs_dir_created) { + root_debugfs_dir = debugfs_create_dir("mailbox",NULL); + if (!root_debugfs_dir) { + dev_err(&pdev->dev, + "Failed to create mailbox debugfs\n"); + return -EINVAL; + } + debugfs_dir_created = true; + } + + debugfs_create_file(file_names[index_names], 0600, root_debugfs_dir, + tdev, &mbox_client_light_message_ops); + + index_names++; + return 0; +} + +static void mbox_client_light_receive_message(struct mbox_client *client, + void *message) +{ + struct mbox_client_light_device *tdev = dev_get_drvdata(client->dev); + char *data = message; + + spin_lock(&tdev->lock); + memcpy(tdev->rx_buffer, data, MBOX_MAX_MSG_LEN); + spin_unlock(&tdev->lock); + print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); +} + +static struct mbox_chan * +mbox_client_light_request_channel(struct platform_device *pdev, + const char *name) +{ + struct mbox_client *client; + struct mbox_chan *channel; + + client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + client->dev = &pdev->dev; + client->tx_block = true; + client->knows_txdone = false; + client->tx_tout = 500; + client->rx_callback = mbox_client_light_receive_message; + + channel = mbox_request_channel_byname(client, name); + if (IS_ERR(channel)) { + devm_kfree(&pdev->dev, client); + dev_warn(&pdev->dev, "Failed to request %s channel\n", name); + return NULL; + } + + return channel; +} + +static int mbox_client_light_probe(struct platform_device *pdev) +{ + struct mbox_client_light_device *tdev; + int ret; + static int chan_idx = 0; + + tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); + if (!tdev) + return -ENOMEM; + + if (!chan_idx) + tdev->tx_channel = mbox_client_light_request_channel(pdev, "902"); + else + tdev->tx_channel = mbox_client_light_request_channel(pdev, "906"); + if (!tdev->tx_channel) { + dev_err(&pdev->dev, "Request channel failed\n"); + return -EPROBE_DEFER; + } + chan_idx++; + /* In fact, rx_channel is same with tx_channel in C-SKY's mailbox */ + tdev->rx_channel = tdev->tx_channel; + + tdev->dev = &pdev->dev; + platform_set_drvdata(pdev, tdev); + + spin_lock_init(&tdev->lock); + + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); + if (!tdev->rx_buffer) + return -ENOMEM; + + ret = mbox_client_light_add_debugfs(pdev, tdev); + if (ret) + return ret; + + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +} + +static int mbox_client_light_remove(struct platform_device *pdev) +{ + struct mbox_client_light_device *tdev = platform_get_drvdata(pdev); + + debugfs_remove_recursive(root_debugfs_dir); + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); + + if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + + return 0; +} + +static const struct of_device_id mbox_client_light_match[] = { + { .compatible = "thead,light-mbox-client" }, + {}, +}; + +static struct platform_driver mbox_client_light_driver = { + .driver = { + .name = "thead,light-mbox-client", + .of_match_table = mbox_client_light_match, + }, + .probe = mbox_client_light_probe, + .remove = mbox_client_light_remove, +}; +module_platform_driver(mbox_client_light_driver); + +MODULE_AUTHOR("Alibaba Group Holding Limited"); +MODULE_DESCRIPTION("Thead Light mailbox IPC client driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mailbox/light-mailbox.c b/drivers/mailbox/light-mailbox.c new file mode 100644 index 00000000000000..f3d34d947ec48d --- /dev/null +++ b/drivers/mailbox/light-mailbox.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Status Register */ +#define LIGHT_MBOX_STA 0x0 +#define LIGHT_MBOX_CLR 0x4 +#define LIGHT_MBOX_MASK 0xc + +/* Transmit/receive data register: + * INFO0 ~ INFO6 + */ +#define LIGHT_MBOX_INFO_NUM 8 +#define LIGHT_MBOX_DATA_INFO_NUM 7 +#define LIGHT_MBOX_INFO0 0x14 +/* Transmit ack register: INFO7 */ +#define LIGHT_MBOX_INFO7 0x30 + +/* Generate remote icu IRQ Register */ +#define LIGHT_MBOX_GEN 0x10 +#define LIGHT_MBOX_GEN_RX_DATA BIT(6) +#define LIGHT_MBOX_GEN_TX_ACK BIT(7) + +#define LIGHT_MBOX_CHAN_RES_SIZE 0x1000 +#define LIGHT_MBOX_CHANS 4 +#define LIGHT_MBOX_CHAN_NAME_SIZE 20 + +#define LIGHT_MBOX_ACK_MAGIC 0xdeadbeaf + +enum light_mbox_chan_type { + LIGHT_MBOX_TYPE_TXRX, /* Tx & Rx chan */ + LIGHT_MBOX_TYPE_DB, /* Tx & Rx doorbell */ +}; + +enum light_mbox_icu_cpu_id { + LIGHT_MBOX_ICU_CPU0, /* 910T */ + LIGHT_MBOX_ICU_CPU1, /* 902 */ + LIGHT_MBOX_ICU_CPU2, /* 906 */ + LIGHT_MBOX_ICU_CPU3, /* 910R */ +}; + +struct light_mbox_con_priv { + enum light_mbox_icu_cpu_id idx; + enum light_mbox_chan_type type; + void __iomem *comm_local_base; + void __iomem *comm_remote_base; + char irq_desc[LIGHT_MBOX_CHAN_NAME_SIZE]; + struct mbox_chan *chan; + struct tasklet_struct txdb_tasklet; +}; + +struct light_mbox_priv { + struct device *dev; + void __iomem *local_icu[LIGHT_MBOX_CHANS]; + void __iomem *remote_icu[LIGHT_MBOX_CHANS - 1]; + void __iomem *cur_cpu_ch_base; + enum light_mbox_icu_cpu_id cur_icu_cpu_id; + spinlock_t mbox_lock; /* control register lock */ + + struct mbox_controller mbox; + struct mbox_chan mbox_chans[LIGHT_MBOX_CHANS]; + + struct light_mbox_con_priv con_priv[LIGHT_MBOX_CHANS]; + struct clk *clk; + int irq; +}; + +static struct light_mbox_priv *to_light_mbox_priv(struct mbox_controller *mbox) +{ + return container_of(mbox, struct light_mbox_priv, mbox); +} + +static void light_mbox_write(struct light_mbox_priv *priv, u32 val, u32 offs) +{ + iowrite32(val, priv->cur_cpu_ch_base + offs); +} + +static u32 light_mbox_read(struct light_mbox_priv *priv, u32 offs) +{ + return ioread32(priv->cur_cpu_ch_base + offs); +} + +static u32 light_mbox_rmw(struct light_mbox_priv *priv, u32 off, u32 set, u32 clr) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->mbox_lock, flags); + val = light_mbox_read(priv, off); + val &= ~clr; + val |= set; + light_mbox_write(priv, val, off); + spin_unlock_irqrestore(&priv->mbox_lock, flags); + + return val; +} + +static void light_mbox_chan_write(struct light_mbox_con_priv *cp, u32 val, u32 offs, bool is_remote) +{ + if (is_remote) + iowrite32(val, cp->comm_remote_base + offs); + else + iowrite32(val, cp->comm_local_base + offs); +} + +static u32 light_mbox_chan_read(struct light_mbox_con_priv *cp, u32 offs, bool is_remote) +{ + if (is_remote) + return ioread32(cp->comm_remote_base + offs); + else + return ioread32(cp->comm_local_base + offs); +} + +static void light_mbox_chan_rmw(struct light_mbox_con_priv *cp, u32 off, u32 set, u32 clr, bool is_remote) +{ + struct light_mbox_priv *priv = to_light_mbox_priv(cp->chan->mbox); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->mbox_lock, flags); + val = light_mbox_chan_read(cp, off, is_remote); + val &= ~clr; + val |= set; + light_mbox_chan_write(cp, val, off, is_remote); + spin_unlock_irqrestore(&priv->mbox_lock, flags); +} + +static void light_mbox_chan_rd_data(struct light_mbox_con_priv *cp, void *data, bool is_remote) +{ + u32 off = LIGHT_MBOX_INFO0; + u32 *arg = data; + u32 i; + + /* read info0 ~ info6, totally 28 bytes + * requires data memory size is 28 bytes + */ + for (i = 0; i < LIGHT_MBOX_DATA_INFO_NUM; i++) { + *arg = light_mbox_chan_read(cp, off, is_remote); + off += 4; + arg++; + } +} + +static void light_mbox_chan_wr_data(struct light_mbox_con_priv *cp, void *data, bool is_remote) +{ + u32 off = LIGHT_MBOX_INFO0; + u32 *arg = data; + u32 i; + + /* write info0 ~ info6, totally 28 bytes + * requires data memory is 28 bytes valid data + */ + for (i = 0; i < LIGHT_MBOX_DATA_INFO_NUM; i++) { + light_mbox_chan_write(cp, *arg, off, is_remote); + off += 4; + arg++; + } +} + +static void light_mbox_chan_wr_ack(struct light_mbox_con_priv *cp, void *data, bool is_remote) +{ + u32 off = LIGHT_MBOX_INFO7; + u32 *arg = data; + + light_mbox_chan_write(cp, *arg, off, is_remote); +} + +static int light_mbox_chan_id_to_mapbit(struct light_mbox_con_priv *cp) +{ + struct light_mbox_priv *priv = to_light_mbox_priv(cp->chan->mbox); + int mapbit = 0; + int i; + + for (i = 0; i < LIGHT_MBOX_CHANS; i++) { + if (i == cp->idx) + return mapbit; + + if (i != priv->cur_icu_cpu_id) + mapbit++; + } + + if (i == LIGHT_MBOX_CHANS) + dev_err(cp->chan->mbox->dev, "convert to mapbit failed\n"); + + return 0; +} + +static void light_mbox_txdb_tasklet(unsigned long data) +{ + struct light_mbox_con_priv *cp = (struct light_mbox_con_priv *)data; + + mbox_chan_txdone(cp->chan, 0); +} + +static irqreturn_t light_mbox_isr(int irq, void *p) +{ + struct mbox_chan *chan = p; + struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); + struct light_mbox_con_priv *cp = chan->con_priv; + int mapbit = light_mbox_chan_id_to_mapbit(cp); + u32 sta, dat[LIGHT_MBOX_DATA_INFO_NUM]; + u32 ack_magic = LIGHT_MBOX_ACK_MAGIC; + u32 info0_data, info7_data; + + sta = light_mbox_read(priv, LIGHT_MBOX_STA); + if (!(sta & BIT(mapbit))) + return IRQ_NONE; + + /* clear chan irq bit in STA register */ + light_mbox_rmw(priv, LIGHT_MBOX_CLR, BIT(mapbit), 0); + + /* rx doorbell */ + if (cp->type == LIGHT_MBOX_TYPE_DB) { + mbox_chan_received_data(cp->chan, NULL); + return IRQ_HANDLED; + } + + /* info0 is the protocol word, shoud not be zero! */ + info0_data = light_mbox_chan_read(cp, LIGHT_MBOX_INFO0, false); + if (info0_data) { + /* read info0~info6 data */ + light_mbox_chan_rd_data(cp, dat, false); + + /* clear local info0 */ + light_mbox_chan_write(cp, 0x0, LIGHT_MBOX_INFO0, false); + + /* notify remote cpu */ + light_mbox_chan_wr_ack(cp, &ack_magic, true); + /* CPU1 902/906 use polling mode to monitor info7 */ + if (cp->idx != LIGHT_MBOX_ICU_CPU1 && cp->idx != LIGHT_MBOX_ICU_CPU2) + light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, LIGHT_MBOX_GEN_TX_ACK, 0, true); + + /* transfer the data to client */ + mbox_chan_received_data(chan, (void *)dat); + } + + /* info7 magic value mean the real ack signal, not generate bit7 */ + info7_data = light_mbox_chan_read(cp, LIGHT_MBOX_INFO7, false); + if (info7_data == LIGHT_MBOX_ACK_MAGIC) { + /* clear local info7 */ + light_mbox_chan_write(cp, 0x0, LIGHT_MBOX_INFO7, false); + + /* notify framework the last TX has completed */ + mbox_chan_txdone(chan, 0); + } + + if (!info0_data && !info7_data) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int light_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct light_mbox_con_priv *cp = chan->con_priv; + + if (cp->type == LIGHT_MBOX_TYPE_DB) + tasklet_schedule(&cp->txdb_tasklet); + else + light_mbox_chan_wr_data(cp, data, true); + light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, LIGHT_MBOX_GEN_RX_DATA, 0, true); + return 0; +} + +static int light_mbox_startup(struct mbox_chan *chan) +{ + struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); + struct light_mbox_con_priv *cp = chan->con_priv; + u32 data[8] = {0}; + int mask_bit; + int ret; + + /* clear local and remote generate and info0~info7 */ + light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, 0x0, 0xff, true); + light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, 0x0, 0xff, false); + light_mbox_chan_wr_ack(cp, &data[7], true); + light_mbox_chan_wr_ack(cp, &data[7], false); + light_mbox_chan_wr_data(cp, &data[0], true); + light_mbox_chan_wr_data(cp, &data[0], false); + + /* enable the chan mask */ + mask_bit = light_mbox_chan_id_to_mapbit(cp); + light_mbox_rmw(priv, LIGHT_MBOX_MASK, BIT(mask_bit), 0); + + if (cp->type == LIGHT_MBOX_TYPE_DB) + /* tx doorbell doesn't have ACK, rx doorbell requires isr */ + tasklet_init(&cp->txdb_tasklet, light_mbox_txdb_tasklet, + (unsigned long)cp); + + ret = request_irq(priv->irq, light_mbox_isr, IRQF_SHARED | + IRQF_NO_SUSPEND, cp->irq_desc, chan); + if (ret) { + dev_err(priv->dev, + "Unable to acquire IRQ %d\n", priv->irq); + return ret; + } + + return 0; +} + +static void light_mbox_shutdown(struct mbox_chan *chan) +{ + struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); + struct light_mbox_con_priv *cp = chan->con_priv; + int mask_bit; + + /* clear the chan mask */ + mask_bit = light_mbox_chan_id_to_mapbit(cp); + light_mbox_rmw(priv, LIGHT_MBOX_MASK, 0, BIT(mask_bit)); + + free_irq(priv->irq, chan); +} + +static const struct mbox_chan_ops light_mbox_ops = { + .send_data = light_mbox_send_data, + .startup = light_mbox_startup, + .shutdown = light_mbox_shutdown, +}; + +static void light_mbox_init_generic(struct light_mbox_priv *priv) +{ + /* Set default configuration */ + light_mbox_write(priv, 0xff, LIGHT_MBOX_CLR); + light_mbox_write(priv, 0x0, LIGHT_MBOX_MASK); +} + +static struct mbox_chan *light_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *sp) +{ + struct light_mbox_priv *priv = to_light_mbox_priv(mbox); + struct light_mbox_con_priv *cp; + u32 chan, type; + + if (sp->args_count != 2) { + dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); + return ERR_PTR(-EINVAL); + } + + chan = sp->args[0]; /* comm remote channel */ + type = sp->args[1]; /* comm channel type */ + + if (chan >= mbox->num_chans) { + dev_err(mbox->dev, "Not supported channel number: %d\n", chan); + return ERR_PTR(-EINVAL); + } + + if (chan == priv->cur_icu_cpu_id) { + dev_err(mbox->dev, "Cannot communicate with yourself\n"); + return ERR_PTR(-EINVAL); + } + + if (type > LIGHT_MBOX_TYPE_DB) { + dev_err(mbox->dev, "Not supported the type for channel[%d]\n", chan); + return ERR_PTR(-EINVAL); + } + + cp = mbox->chans[chan].con_priv; + cp->type = type; + + return &mbox->chans[chan]; +} + +static int light_mbox_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct light_mbox_priv *priv; + struct resource *res; + unsigned int remote_idx = 0; + unsigned int i; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (of_property_read_u32(np, "icu_cpu_id", &priv->cur_icu_cpu_id)) { + dev_err(dev, "icu_cpu_id is missing\n"); + return -EINVAL; + } + + if (priv->cur_icu_cpu_id != LIGHT_MBOX_ICU_CPU0 && + priv->cur_icu_cpu_id != LIGHT_MBOX_ICU_CPU3) { + dev_err(dev, "icu_cpu_id is invalid\n"); + return -EINVAL; + } + + priv->dev = dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "local_base"); + priv->local_icu[LIGHT_MBOX_ICU_CPU0] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->local_icu[LIGHT_MBOX_ICU_CPU0])) + return PTR_ERR(priv->local_icu[LIGHT_MBOX_ICU_CPU0]); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu0"); + priv->remote_icu[0] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->remote_icu[0])) + return PTR_ERR(priv->remote_icu[0]); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu1"); + priv->remote_icu[1] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->remote_icu[1])) + return PTR_ERR(priv->remote_icu[1]); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu2"); + priv->remote_icu[2] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->remote_icu[2])) + return PTR_ERR(priv->remote_icu[2]); + + priv->local_icu[LIGHT_MBOX_ICU_CPU1] = priv->local_icu[LIGHT_MBOX_ICU_CPU0] + + LIGHT_MBOX_CHAN_RES_SIZE; + priv->local_icu[LIGHT_MBOX_ICU_CPU2] = priv->local_icu[LIGHT_MBOX_ICU_CPU1] + + LIGHT_MBOX_CHAN_RES_SIZE; + priv->local_icu[LIGHT_MBOX_ICU_CPU3] = priv->local_icu[LIGHT_MBOX_ICU_CPU2] + + LIGHT_MBOX_CHAN_RES_SIZE; + + priv->cur_cpu_ch_base = priv->local_icu[priv->cur_icu_cpu_id]; + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) + return priv->irq; + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + if (PTR_ERR(priv->clk) != -ENOENT) + return PTR_ERR(priv->clk); + + priv->clk = NULL; + } + + ret = clk_prepare_enable(priv->clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + + /* init the chans */ + for (i = 0; i < LIGHT_MBOX_CHANS; i++) { + struct light_mbox_con_priv *cp = &priv->con_priv[i]; + + cp->idx = i; + cp->chan = &priv->mbox_chans[i]; + priv->mbox_chans[i].con_priv = cp; + snprintf(cp->irq_desc, sizeof(cp->irq_desc), + "light_mbox_chan[%i]", cp->idx); + + cp->comm_local_base = priv->local_icu[i]; + if (i != priv->cur_icu_cpu_id) { + cp->comm_remote_base = priv->remote_icu[remote_idx]; + remote_idx++; + } + } + + spin_lock_init(&priv->mbox_lock); + + priv->mbox.dev = dev; + priv->mbox.ops = &light_mbox_ops; + priv->mbox.chans = priv->mbox_chans; + priv->mbox.num_chans = LIGHT_MBOX_CHANS; + priv->mbox.of_xlate = light_mbox_xlate; + priv->mbox.txdone_irq = true; + + platform_set_drvdata(pdev, priv); + + light_mbox_init_generic(priv); + + return devm_mbox_controller_register(dev, &priv->mbox); +} + +static int light_mbox_remove(struct platform_device *pdev) +{ + struct light_mbox_priv *priv = platform_get_drvdata(pdev); + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static const struct of_device_id light_mbox_dt_ids[] = { + { .compatible = "thead,light-mbox" }, + { }, +}; +MODULE_DEVICE_TABLE(of, light_mbox_dt_ids); + +static struct platform_driver light_mbox_driver = { + .probe = light_mbox_probe, + .remove = light_mbox_remove, + .driver = { + .name = "light_mbox", + .of_match_table = light_mbox_dt_ids, + }, +}; +module_platform_driver(light_mbox_driver); + +MODULE_AUTHOR("fugang.duan "); +MODULE_DESCRIPTION("Thead Light mailbox IPC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 965d4f0c18a6c0..8a2c579c783cfc 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1663,4 +1663,13 @@ config REGULATOR_QCOM_LABIBB boost regulator and IBB can be used as a negative boost regulator for LCD display panel. +config REGULATOR_LIGHT_AON + tristate "Thead Light Aon regulator" + depends on LIGHT_AON + default y + help + This driver provides support for the thead light virtal regulators that + inmplemented on Light Aon system. + + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 23074714a81a3e..aa1d8ca5949938 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -195,5 +195,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o +obj-$(CONFIG_REGULATOR_LIGHT_AON) += light-regulator-aon.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/light-regulator-aon.c b/drivers/regulator/light-regulator-aon.c new file mode 100644 index 00000000000000..d30cb956145bba --- /dev/null +++ b/drivers/regulator/light-regulator-aon.c @@ -0,0 +1,888 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MBOX_MAX_MSG_LEN 28 + +#define CONFIG_AON_REG_DEBUG 1 + +struct rpc_msg_regu_vol_set { + u16 regu_id; ///< virtual regu id + u16 is_dual_rail; ///< whether this regu has dual rails + u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail + u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false + u16 reserved[6]; +} __packed __aligned(4); + +struct rpc_msg_regu_vol_get { + u16 regu_id; ///< virtual regu id + u16 is_dual_rail; ///< whether this regu has dual rails + u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail + u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false + u16 reserved[6]; + +} __packed __aligned(4); + +struct rpc_msg_regu_pwr_set { + u16 regu_id; ///< virtual regu id + u16 status; ///< 0: power off; 1: powr on + u32 reserved[5]; +} __packed __aligned(4); + +struct rpc_msg_regu_pwr_get { + u16 regu_id; ///< virtual regu id + u16 status; ///< 0: power off; 1: powr on + u32 reserved[5]; + +} __packed __aligned(4); + +struct light_aon_msg_regulator_ctrl { + struct light_aon_rpc_msg_hdr hdr; + union rpc_func_t { + struct rpc_msg_regu_vol_set regu_vol_set; + struct rpc_msg_regu_vol_get regu_vol_get; + struct rpc_msg_regu_pwr_set regu_pwr_set; + struct rpc_msg_regu_pwr_get regu_pwr_get; + } __packed __aligned(4) rpc; +} __packed __aligned(4); + +enum pm_resource { + SOC_DVDD18_AON, /*da9063: ldo-3 */ + SOC_AVDD33_USB3, /*da9063: ldo-9 */ + SOC_DVDD08_AON, /*da9063: ldo-2 */ + SOC_APCPU_DVDD_DVDDM,/*da9063: vbcore1 & vbcore2*/ + SOC_DVDD08_DDR, /*da9063: buckperi */ + SOC_VDD_DDR_1V8, /*da9063: ldo-4 */ + SOC_VDD_DDR_1V1, /*da9063: buckmem & buckio */ + SOC_VDD_DDR_0V6, /*da9063: buckpro */ + SOC_DVDD18_AP, /*da9063: ldo-11 */ + SOC_DVDD08_AP, /*da9121: da9121_ex */ + SOC_AVDD08_MIPI_HDMI,/*da9063: ldo-1 */ + SOC_AVDD18_MIPI_HDMI,/*da9063: ldo-5 */ + SOC_DVDD33_EMMC, /*da9063: ldo-10 */ + SOC_DVDD18_EMMC, /*slg51000:ldo-3 */ + SOC_DOVDD18_SCAN, /*da9063: ldo-6 */ + SOC_VEXT_2V8, /*da9063: ldo-7 */ + SOC_DVDD12_SCAN, /*da9063: ld0-8 */ + SOC_AVDD28_SCAN_EN, /*da9063: gpio4 */ + SOC_AVDD28_RGB, /*slg51000:ldo-1 */ + SOC_DOVDD18_RGB, /*slg51000:ldo-4 */ + SOC_DVDD12_RGB, /*slg51000:ldo-5 */ + SOC_AVDD25_IR, /*slg51000:ldo-2 */ + SOC_DOVDD18_IR, /*slg51000:ldo-7 */ + SOC_DVDD12_IR, /*slg51000:ldo-6 */ + SOC_ADC_VREF, + SOC_LCD0_EN, + SOC_VEXT_1V8, + + + SOC_REGU_MAX +}; + +struct apcpu_vol_set { + u32 vdd; ///< cpu core voltage + u32 vddm; ///< cpu core-mem voltage +}; + +struct aon_regu_desc { + struct regulator_desc *regu_desc; ///< discription of regulator + u32 regu_num; ///< element number of regulators,which point to regu-dsc-array +}; + +struct aon_regu_info { + struct device *dev; + const struct apcpu_vol_set *cpu_vol; ///< signed-off voltage of cpu + u32 vddm; ///< cpu-mem voltage + struct aon_regu_desc *regu_desc; ///< regu-desc set + struct light_aon_ipc *ipc_handle; ///< handle of mail-box +}; + +static struct aon_regu_info light_aon_pmic_info; + +#define APCPU_VOL_DEF(_vdd, _vddm) \ + { \ + .vdd = _vdd, \ + .vddm = _vddm, \ + } + +static const struct apcpu_vol_set apcpu_volts[] = { + /*300Mhz*/ + APCPU_VOL_DEF(600000U, 750000U), + APCPU_VOL_DEF(600000U, 800000U), + APCPU_VOL_DEF(650000U, 800000U), + APCPU_VOL_DEF(720000U, 770000U), + /*800Mhz*/ + APCPU_VOL_DEF(700000U,800000U), + APCPU_VOL_DEF(720000U,820000U), + /*1500Mhz*/ + APCPU_VOL_DEF(800000U,800000U), + APCPU_VOL_DEF(820000U,820000U), + /*1850Mhz*/ + APCPU_VOL_DEF(1000000U,1000000U), +}; + +/* dc2 is valid when is_dual_rail is true + * + * dual-rail regulator means that a virtual regulator involes two hw-regulators + */ +static int aon_set_regulator(struct light_aon_ipc *ipc, u16 regu_id, + u32 dc1, u32 dc2, u16 is_dual_rail) +{ + struct light_aon_msg_regulator_ctrl msg = {0}; + struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; + + hdr->ver = LIGHT_AON_RPC_VERSION; + hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; + hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR; + hdr->size = LIGHT_AON_RPC_MSG_NUM; + + msg.rpc.regu_vol_set.regu_id = regu_id; + msg.rpc.regu_vol_set.is_dual_rail = is_dual_rail; + msg.rpc.regu_vol_set.dc1 = dc1; + msg.rpc.regu_vol_set.dc2 = dc2; + + return light_aon_call_rpc(ipc, &msg, true); +} + +/* dc2 is valid when is_dual_rail is true + * + * dual-rail regulator means that a virtual regulator involes two hw-regulators + */ +static int aon_get_regulator(struct light_aon_ipc *ipc, u16 regu_id, + u32 *dc1, u32 *dc2, u16 is_dual_rail) +{ + struct light_aon_msg_regulator_ctrl msg = {0}; + struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; + int ret; + + hdr->ver = LIGHT_AON_RPC_VERSION; + hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; + hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR; + hdr->size = LIGHT_AON_RPC_MSG_NUM; + msg.rpc.regu_vol_get.regu_id = regu_id; + msg.rpc.regu_vol_get.is_dual_rail = is_dual_rail; + + ret = light_aon_call_rpc(ipc, &msg, true); + if (ret) + return ret; + + if (dc1 != NULL) + *dc1 = msg.rpc.regu_vol_get.dc1; + + if (dc2 != NULL) + *dc2 = msg.rpc.regu_vol_get.dc2; + + return 0; +} + +static int aon_regu_power_ctrl(struct light_aon_ipc *ipc,u32 regu_id,u16 pwr_on) +{ + struct light_aon_msg_regulator_ctrl msg = {0}; + struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; + + hdr->ver = LIGHT_AON_RPC_VERSION; + hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; + hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_SET; + hdr->size = LIGHT_AON_RPC_MSG_NUM; + + msg.rpc.regu_pwr_set.regu_id = regu_id; + msg.rpc.regu_pwr_set.status = pwr_on; + return light_aon_call_rpc(ipc, &msg, true); +} +static int aon_regu_dummy_enable(struct regulator_dev *reg) +{ + return 0; +} +static int aon_regu_dummy_disable(struct regulator_dev *reg) +{ + return 0; +} +static int aon_regu_dummy_is_enabled(struct regulator_dev *reg) +{ + return 0; +} +static int aon_regu_enable(struct regulator_dev *reg) +{ + u16 regu_id =(u16) rdev_get_id(reg); + return aon_regu_power_ctrl(light_aon_pmic_info.ipc_handle, regu_id, 1); +} + +static int aon_regu_disable(struct regulator_dev *reg) +{ + u16 regu_id =(u16) rdev_get_id(reg); + return aon_regu_power_ctrl(light_aon_pmic_info.ipc_handle, regu_id, 0); +} + +static int aon_regu_is_enabled(struct regulator_dev *reg) +{ + struct light_aon_msg_regulator_ctrl msg = {0}; + struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; + int ret; + u16 regu_id =(u16) rdev_get_id(reg); + + hdr->ver = LIGHT_AON_RPC_VERSION; + hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; + hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_GET; + hdr->size = LIGHT_AON_RPC_MSG_NUM; + + msg.rpc.regu_pwr_get.regu_id = regu_id; + ret = light_aon_call_rpc(light_aon_pmic_info.ipc_handle, &msg, true); + if (ret < 0) { + return ret; + } + + return (int) msg.rpc.regu_pwr_get.status; +} + +static int aon_regu_set_voltage(struct regulator_dev *reg, + int minuV, int uV, unsigned *selector) +{ + u16 regu_id =(u16) rdev_get_id(reg); + u32 voltage = minuV; /* uV */ + int err; + + pr_debug("[%s,%d]minuV = %d, uV = %d\n", __func__, __LINE__, minuV, uV); + + err = aon_set_regulator(light_aon_pmic_info.ipc_handle, regu_id, + voltage, 0, 0); + if (err) { + pr_err("failed to set Voltages to %d!\n", minuV); + return -EINVAL; + } + + return 0; +} + +static int aon_regu_get_voltage(struct regulator_dev *reg) +{ + u16 regu_id = (u16) rdev_get_id(reg); + int voltage, ret; + + ret = aon_get_regulator(light_aon_pmic_info.ipc_handle, regu_id, + &voltage, NULL, 0); + if (ret) { + pr_err("failed to get voltage\n"); + return -EINVAL; + } + + pr_debug("[%s,%d]voltage = %d\n", __func__, __LINE__, voltage); + + return voltage; +} + +static const struct apcpu_vol_set *apcpu_get_matched_signed_off_voltage(u32 vdd, u32 vddm) +{ + int vol_count = ARRAY_SIZE(apcpu_volts); + int i; + + for (i = 0; i < vol_count; i++) + if ((vdd == apcpu_volts[i].vdd) && + (vddm == apcpu_volts[i].vddm)) + return &apcpu_volts[i]; + +#ifdef CONFIG_AON_REG_DEBUG + return &apcpu_volts[2]; +#else + return NULL; +#endif +} + +static int apcpu_set_vdd_vddm_voltage(struct regulator_dev *reg, + int minuV, int uV, unsigned *selector) +{ + struct aon_regu_info *info = rdev_get_drvdata(reg); + const struct apcpu_vol_set *cpu_vol; + u32 vol = minuV; /* uV */ + u32 dc1, dc2; + int err; + + cpu_vol = apcpu_get_matched_signed_off_voltage(vol, light_aon_pmic_info.vddm); + if (!cpu_vol) { + dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n"); +#ifndef CONFIG_AON_REG_DEBUG + return -EINVAL; +#endif + } + + dc1 = cpu_vol->vdd; + dc2 = cpu_vol->vddm; + info->cpu_vol = cpu_vol; + info->vddm = cpu_vol->vddm; + + err = aon_set_regulator(light_aon_pmic_info.ipc_handle, (u16)SOC_APCPU_DVDD_DVDDM, + dc1, dc2, 1); + if (err) { + dev_err(info->dev, "failed to set Voltages to %d!\n", uV); + return -EINVAL; + } + + return 0; +} + +static int apcpu_set_vddm_voltage(struct regulator_dev *reg, + int minuV, int uV, unsigned *selector) +{ + struct aon_regu_info *info = rdev_get_drvdata(reg); + int bcore_table_count = ARRAY_SIZE(apcpu_volts); + u32 vol = minuV; /* uV */ + int i; + + for (i = 0; i < bcore_table_count; i++) + if (vol == apcpu_volts[i].vddm) + break; + + if (i >= bcore_table_count) { + dev_err(info->dev, "The vol is not existed in matching table\n"); +#ifndef CONFIG_AON_REG_DEBUG + return -EINVAL; +#endif + } + + /* update the vddm */ + info->vddm = vol; + return 0; +} + +static int apcpu_get_voltage(struct regulator_dev *reg, bool is_vdd) +{ + struct aon_regu_info *info = rdev_get_drvdata(reg); + const struct apcpu_vol_set *cpu_vol; + u32 dc1, dc2; + int err; + + err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, + &dc1, &dc2, 1); + if (err) { + dev_err(info->dev, "failed to get Voltages!\n"); + return -EINVAL; + } + cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); + if (!cpu_vol) { + dev_err(info->dev, "Voltage [%d:%d] is not existing in matching table\n", dc1, dc2); + return -EINVAL; + } + + info->cpu_vol = cpu_vol; + + return is_vdd ? cpu_vol->vdd : cpu_vol->vddm; +} + +static int apcpu_get_vdd_voltage(struct regulator_dev *reg) +{ + return apcpu_get_voltage(reg, true); +} + +static int apcpu_get_vddm_voltage(struct regulator_dev *reg) +{ + return apcpu_get_voltage(reg, false); +} + +static const struct regulator_ops regu_common_ops = { + .enable = aon_regu_enable, + .disable = aon_regu_disable, + .is_enabled = aon_regu_is_enabled, + .list_voltage = regulator_list_voltage_linear, + .set_voltage = aon_regu_set_voltage, + .get_voltage = aon_regu_get_voltage, +}; +static const struct regulator_ops apcpu_dvdd_ops = { + .enable = aon_regu_dummy_enable, + .disable = aon_regu_dummy_disable, + .is_enabled = aon_regu_dummy_is_enabled, + .list_voltage = regulator_list_voltage_linear, + .set_voltage = apcpu_set_vdd_vddm_voltage, + .get_voltage = apcpu_get_vdd_voltage, +}; + +static const struct regulator_ops apcpu_dvddm_ops = { + .enable = aon_regu_dummy_enable, + .disable = aon_regu_dummy_disable, + .is_enabled = aon_regu_dummy_is_enabled, + .list_voltage = regulator_list_voltage_linear, + .set_voltage = apcpu_set_vddm_voltage, + .get_voltage = apcpu_get_vddm_voltage, +}; + +/* Macros for voltage DC/DC converters (BUCKs) for cpu */ +#define REGU_DSC_DEF(regu_id, of_math_name) \ + .id = regu_id, \ + .name = #regu_id, \ + .of_match = of_match_ptr(__stringify(of_math_name)), \ + .ops = ®u_common_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE + +#define BUCK_APCPU_DVDD(regu_id,min_mV, step_mV, max_mV) \ + .id = regu_id, \ + .name = "APCPU_DVDD", \ + .of_match = of_match_ptr("appcpu_dvdd"), \ + .ops = &apcpu_dvdd_ops, \ + .min_uV = (min_mV), \ + .uV_step = (step_mV), \ + .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE + +#define BUCK_APCPU_DVDDM(regu_id, min_mV, step_mV, max_mV) \ + .id = regu_id, \ + .name = "APCPU_DVDDM", \ + .of_match = of_match_ptr("appcpu_dvddm"), \ + .ops = &apcpu_dvddm_ops, \ + .min_uV = (min_mV) , \ + .uV_step = (step_mV), \ + .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE + +/* regulator desc for dialog */ +static struct regulator_desc light_dialog_ant_regu_desc[] = { + /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ + { + BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), + }, + { + BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), + }, + + /*common regu ,no need to adjust vol dynamicaly */ + { + REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), + }, + { + REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), + }, + { + REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), + }, + { + REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), + }, + { + REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), + }, + { + REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), + }, + { + REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), + }, + { + REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), + }, + { + REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), + }, + { + REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), + }, + { + REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan), + }, + { + REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan), + }, + { + REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en), + }, +}; + +static struct regulator_desc light_dialog_regu_desc[] = { + /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ + { + BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), + }, + { + BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), + }, + + /*common regu ,no need to adjust vol dynamicaly */ + { + REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), + }, + { + REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), + }, + { + REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), + }, + { + REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), + }, + { + REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), + }, + { + REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), + }, + { + REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), + }, + { + REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), + }, + { + REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), + }, + { + REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), + }, + { + REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan), + }, + { + REGU_DSC_DEF(SOC_VEXT_2V8,soc_vext_2v8), + }, + { + REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan), + }, + { + REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en), + }, + { + REGU_DSC_DEF(SOC_AVDD28_RGB,soc_avdd28_rgb), + }, + { + REGU_DSC_DEF(SOC_DOVDD18_RGB,soc_dovdd18_rgb), + }, + { + REGU_DSC_DEF(SOC_DVDD12_RGB,soc_dvdd12_rgb), + }, + { + REGU_DSC_DEF(SOC_AVDD25_IR,soc_avdd25_ir), + }, + { + REGU_DSC_DEF(SOC_DOVDD18_IR,soc_dovdd18_ir), + }, + { + REGU_DSC_DEF(SOC_DVDD12_IR,soc_dvdd12_ir), + }, +}; + +/* regulator desc for ricoh */ +static struct regulator_desc light_ricoh_regu_desc[] = { + /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ + { + BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000), + }, + { + BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000), + }, + + /*common regu ,no need to adjust vol dynamicaly */ + { + REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), + }, + { + REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), + }, + { + REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), + }, + { + REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), + }, + { + REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), + }, + { + REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), + }, + { + REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), + }, + { + REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), + }, + { + REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), + }, + { + REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), + }, + { + REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), + }, + { + REGU_DSC_DEF(SOC_LCD0_EN,soc_lcd0_en), + }, + { + REGU_DSC_DEF(SOC_VEXT_1V8,soc_vext_1v8), + }, +}; + +#define GEN_REGISTER_SHOW(x, y) \ +static ssize_t x##_registers_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct platform_device *pdev = to_platform_device(dev); \ + struct aon_regu_info *info = platform_get_drvdata(pdev); \ + u32 dc1, dc2; \ + ssize_t ret; \ + \ + ret = aon_get_regulator(light_aon_pmic_info.ipc_handle, y, \ + &dc1, &dc2, 0); \ + if (ret) { \ + dev_err(info->dev, "failed to get Voltages!\n"); \ + return -EINVAL; \ + } \ + \ + ret = sprintf(buf, "%u\n", dc1); \ + return ret; \ +} + +#define GEN_REGISTER_STORE(x, y) \ +static ssize_t x##_register_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct platform_device *pdev = to_platform_device(dev); \ + struct aon_regu_info *info = platform_get_drvdata(pdev); \ + unsigned long dc1, dc2 = 0; \ + int err; \ + \ + if (kstrtoul(buf, 0, &dc1)) \ + return -EINVAL; \ + \ + err = aon_set_regulator(light_aon_pmic_info.ipc_handle, y, \ + dc1, dc2, 0); \ + if (err) { \ + dev_err(info->dev, "failed to set Voltages to [%lu]!\n", dc1); \ + return -EINVAL; \ + } \ + \ + return count; \ +} + +static ssize_t soc_apcpu_dvdd_dvddm_registers_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct aon_regu_info *info = platform_get_drvdata(pdev); + size_t bufpos = 0, count = 26; + const struct apcpu_vol_set *cpu_vol; + u32 dc1, dc2; + int i = 0; + int err; + err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, + &dc1, &dc2, 1); + if (err) { + dev_err(info->dev, "failed to get Voltages!\n"); + return -EINVAL; + } + cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); + if (!cpu_vol) + dev_err(info->dev, "Read [%d:%d] is not existing in matching table\n", dc1, dc2); + snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i); + bufpos += 4; + snprintf(buf + bufpos, count - bufpos, "%u", dc1); + bufpos += 8; + buf[bufpos++] = '\n'; + i++; + snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i); + bufpos += 4; + snprintf(buf + bufpos, count - bufpos, "%u", dc2); + bufpos += 8; + buf[bufpos++] = '\n'; + return bufpos; +} +static ssize_t soc_apcpu_dvdd_dvddm_register_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct platform_device *pdev = to_platform_device(dev); + struct aon_regu_info *info = platform_get_drvdata(pdev); + const struct apcpu_vol_set *cpu_vol; + char *start = (char *)buf; + unsigned long dc1, dc2; + int err; + while (*start == ' ') + start++; + dc1 = simple_strtoul(start, &start, 0); + while (*start == ' ') + start++; + if (kstrtoul(start, 0, &dc2)) + return -EINVAL; + cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); + if (!cpu_vol) { + dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n"); +#ifndef CONFIG_AON_REG_DEBUG + return -EINVAL; +#endif + } + info->cpu_vol = cpu_vol; + info->vddm = cpu_vol->vddm; + err = aon_set_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, + dc1, dc2, 1); + if (err) { + dev_err(info->dev, "failed to set Voltages to [%lu,%lu]!\n", dc1, dc2); +#ifndef CONFIG_AON_REG_DEBUG + return -EINVAL; +#endif + } + return size; +} + +GEN_REGISTER_SHOW(soc_dvdd18_aon, SOC_DVDD18_AON) +GEN_REGISTER_STORE(soc_dvdd18_aon, SOC_DVDD18_AON) +GEN_REGISTER_SHOW(soc_dvdd08_ap, SOC_DVDD08_AP) +GEN_REGISTER_STORE(soc_dvdd08_ap, SOC_DVDD08_AP) +GEN_REGISTER_SHOW(soc_dvdd18_emmc, SOC_DVDD18_EMMC) +GEN_REGISTER_STORE(soc_dvdd18_emmc, SOC_DVDD18_EMMC) +GEN_REGISTER_SHOW(soc_dvdd33_emmc, SOC_DVDD33_EMMC) +GEN_REGISTER_STORE(soc_dvdd33_emmc, SOC_DVDD33_EMMC) + +static DEVICE_ATTR(soc_dvdd18_aon_regs, 0644, soc_dvdd18_aon_registers_show, soc_dvdd18_aon_register_store); +static DEVICE_ATTR(soc_dvdd08_ap_regs, 0644, soc_dvdd08_ap_registers_show, soc_dvdd08_ap_register_store); +static DEVICE_ATTR(soc_dvdd33_emmc_regs, 0644, soc_dvdd33_emmc_registers_show, soc_dvdd33_emmc_register_store); +static DEVICE_ATTR(soc_dvdd18_emmc_regs, 0644, soc_dvdd18_emmc_registers_show, soc_dvdd18_emmc_register_store); +static DEVICE_ATTR(soc_apcpu_dvdd_dvddm_regs, 0644, soc_apcpu_dvdd_dvddm_registers_show, soc_apcpu_dvdd_dvddm_register_store); + +static struct attribute *aon_regs_sysfs_entries[] = { + &dev_attr_soc_dvdd18_aon_regs.attr, + &dev_attr_soc_dvdd08_ap_regs.attr, + &dev_attr_soc_dvdd33_emmc_regs.attr, + &dev_attr_soc_dvdd18_emmc_regs.attr, + &dev_attr_soc_apcpu_dvdd_dvddm_regs.attr, + NULL +}; +static const struct attribute_group dev_attr_aon_regs_group = { + .attrs = aon_regs_sysfs_entries, +}; + + +static const struct aon_regu_desc light_dialog_regus = { + .regu_desc = (struct regulator_desc*) &light_dialog_regu_desc, + .regu_num = ARRAY_SIZE(light_dialog_regu_desc), +}; + +static const struct aon_regu_desc light_dialog_ant_regus = { + .regu_desc = (struct regulator_desc*) &light_dialog_ant_regu_desc, + .regu_num = ARRAY_SIZE(light_dialog_ant_regu_desc), +}; + +static const struct aon_regu_desc light_ricoh_regus = { + .regu_desc = (struct regulator_desc*)&light_ricoh_regu_desc, + .regu_num = ARRAY_SIZE(light_ricoh_regu_desc), +}; + +static int light_aon_regulator_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct regulator_config config = { }; + int i; + int ret; + struct aon_regu_desc *regus_set = NULL; + + if (!np) + return -ENODEV; + + regus_set = (struct aon_regu_desc*)of_device_get_match_data(&pdev->dev); + if (!regus_set) { + return -ENODEV; + } + + /*get ipc handle */ + ret = light_aon_get_handle(&(light_aon_pmic_info.ipc_handle)); + if (ret) { + dev_err(&pdev->dev, "failed to get ipc_handle\n"); + return ret; + } + + /*init private drv data */ + light_aon_pmic_info.dev = &pdev->dev; + light_aon_pmic_info.regu_desc = regus_set; + light_aon_pmic_info.cpu_vol = &apcpu_volts[2]; /* pmic default voltages */ + light_aon_pmic_info.vddm = light_aon_pmic_info.cpu_vol->vddm; + + /*register all regulators*/ + config.dev = &pdev->dev; + config.driver_data = &light_aon_pmic_info; + for (i = 0; i < regus_set->regu_num; i++) { + struct regulator_dev *rdev; + struct regulator_desc *desc; + + desc = ®us_set->regu_desc[i]; + rdev = devm_regulator_register(&pdev->dev, desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "Failed to initialize regulator-%d\n", i); + return PTR_ERR(rdev); + } + } + + i = sysfs_create_group(&config.dev->kobj, &dev_attr_aon_regs_group); + if (i) { + dev_err(&pdev->dev, "Failed to create aon regs debug sysfs.\n"); + return i; + } + + platform_set_drvdata(pdev, &light_aon_pmic_info); + + return 0; +} + +static const struct of_device_id light_pmic_dev_id[] = { + { .compatible = "thead,light-dialog-pmic-ant", .data = &light_dialog_ant_regus}, + { .compatible = "thead,light-dialog-pmic", .data = &light_dialog_regus}, + { .compatible = "thead,light-ricoh-pmic", .data = &light_ricoh_regus}, + {}, +}; +MODULE_DEVICE_TABLE(of, light_pmic_dev_id); + +static struct platform_driver light_aon_regulator_driver = { + .driver = { + .name = "light-aon-reg", + .owner = THIS_MODULE, + .of_match_table = light_pmic_dev_id, + }, + .probe = light_aon_regulator_probe, +}; + +module_platform_driver(light_aon_regulator_driver); + +MODULE_AUTHOR("fugang.duan "); +MODULE_AUTHOR("linghui.zlh "); +MODULE_DESCRIPTION("Thead Light Aon regulator virtual driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/clock/light-dspsys.h b/include/dt-bindings/clock/light-dspsys.h new file mode 100644 index 00000000000000..6473e12623c654 --- /dev/null +++ b/include/dt-bindings/clock/light-dspsys.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#ifndef _LIGHT_DSPSYS_H +#define _LIGHT_DSPSYS_H + +#define CLKGEN_DSP0_PCLK 0 +#define CLKGEN_DSP0_CCLK 1 +#define CLKGEN_DSP1_PCLK 2 +#define CLKGEN_DSP1_CCLK 3 +#define CLKGEN_X2X_X4_DSPSLV_DSP0_ACLK_M 4 +#define CLKGEN_X2X_X4_DSPSLV_DSP1_ACLK_M 5 +#define CLKGEN_AXI4_DSPSYS_SLV_ACLK 6 +#define CLKGEN_AXI4_DSPSYS_ACLK 7 +#define CLKGEN_IOPMP_DSP0_PCLK 8 +#define CLKGEN_IOPMP_DSP1_PCLK 9 +#define CLKGEN_AXI4_DSPSYS_SLV_PCLK 10 +#define CLKGEN_AXI4_DSPSYS_PCLK 11 +#define CLKGEN_X2X_DSP0_ACLK_S 12 +#define CLKGEN_X2X_DSP2_ACLK_S 13 +#define LIGHT_CLKGEN_DSPSYS_CLK_END 14 + +#endif diff --git a/include/dt-bindings/clock/light-fm-ap-clock.h b/include/dt-bindings/clock/light-fm-ap-clock.h new file mode 100644 index 00000000000000..8bb23b690f9818 --- /dev/null +++ b/include/dt-bindings/clock/light-fm-ap-clock.h @@ -0,0 +1,513 @@ +#ifndef _APSYS_CLKGEN_H +#define _APSYS_CLKGEN_H + +#define C910_CCLK_I0 0 +#define AXI4_CPUSYS1_ACLK 1 +#define CLKGEN_GPIO2_DBCLK 2 +#define CLKGEN_MBOX0_PCLK 3 +#define CLKGEN_GMAC0_CCLK 4 +#define CLKGEN_SPI_PCLK 5 +#define CLKGEN_CLK_OUT_1_CLK 6 +#define PAD_RTC_CLK 7 +#define CLKGEN_SPINLOCK_HCLK 8 +#define CLKGEN_QSPI1_PCLK 9 +#define CLKGEN_HDMI_ISCAN_CK_REF_CLK 10 +#define CLKGEN_IOPMP_AON_PCLK 11 +#define CLKGEN_ISP_RY_ACLK 12 +#define CLKGEN_MIPIDSI0_SCANRXCLKESC 13 +#define CLKGEN_EIP120SII_HCLK 14 +#define CLKGEN_MIPI_CSI0_PIXCLK 15 +#define CLKGEN_SRAM_AXI_ACLK_3 16 +#define CLKGEN_PERISYS_AHB_HCLK 17 +#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_CLK 18 +#define CLKGEN_QSPI0_SSI_CLK 19 +#define CLKGEN_DW200_ACLK 20 +#define CLKGEN_IOPMP_EIP120SIII_PCLK 21 +#define VISYS_MIPI_CSI2_CFGCLK 22 +#define CLKGEN_APB3_CPUSYS_HCLK 23 +#define CLKGEN_PERISYS_APB1_HCLK 24 +#define CLKGEN_GPU_CORE_CLK 25 +#define CLKGEN_USB3_DRD_ACLK 26 +#define CLKGEN_VISYS_ACLK 27 +#define CLKGEN_USB3_DRD_CTRL_REF_CLK 28 +#define CLKGEN_TEE_DMAC_ACLK 29 +#define CLKGEN_AUDIO_SUBSYS_ACLK_CP2AP 30 +#define CLKGEN_SRAM_AXI_ACLK_2 31 +#define CLKGEN_IOPMP_VOSYS_GPU_PCLK 32 +#define CLKGEN_CFG2TEE_X2H_ACLK 33 +#define CLKGEN_SRAM_AXI_ACLK_1 34 +#define MISC_SDIO0_OSC_CLK 35 +#define CLKGEN_SDIO0_ACLK 36 +#define CLKGEN_MIPI_DSI1_CFGCLK 37 +#define APB3_CPUSYS_PCLK 38 +#define CLKGEN_TEE_DMAC_HCLK 39 +#define VOSYS_DPU0_PIXELCLK 40 +#define CLKGEN_CPU2CFG_X2H_MHCLK 41 +#define CLKGEN_VPSYS_ACLK 42 +#define CLKGEN_MIPIDSI1_SCANRXCLKESC 43 +#define CLKGEN_MISC2VP_X2X_ACLK_S 44 +#define CLKGEN_MIPI_CSI_SCANBYTECLK 45 +#define CLKGEN_APB3_TEESYS_HCLK 46 +#define VENC_CCLK 47 +#define VPSYS_VDEC_CCLK 48 +#define CLKGEN_MIPI_CSI0_CFG_CLK 49 +#define CLKGEN_MISCSYS_BUS_CLK 50 +#define CLKGEN_DPU_HCLK 51 +#define CLKGEN_UART1_SCLK 52 +#define GMAC_PLL_FOUTPOSTDIV 53 +#define MISC_BUS_CLK 54 +#define CLKGEN_USB3_DRD_SPDCLK 55 +#define CLKGEN_MIPI_CSI2_CFG_CLK 56 +#define CLKGEN_TOP_AXI4S_ACLK 57 +#define CLKGEN_IOPMP_EIP120SII_ACLK 58 +#define CORE_CLK 59 +#define CLKGEN_VPSYS_FCE_ACLK 60 +#define CLKGEN_I2C3_PCLK 61 +#define DPU1_PLL_DIV_CLK 62 +#define CLKGEN_USB3_DRD_PHY_REF_CLK 63 +#define CLKGEN_AON2CPU_A2X_ACLK 64 +#define CLKGEN_QSPI1_SSI_CLK 65 +#define CLKGEN_DPU_CCLK 66 +#define VISYS_MASTER_BUS_ACLK 67 +#define CLKGEN_PERI_I2S_SRC_CLK_0 68 +#define VOSYS_ACLK_M 69 +#define TEESYS_I0_HCLK 70 +#define CLKGEN_MIPI_DSI1_REFCLK 71 +#define CLKGEN_MIPI_DSI0_PCLK 72 +#define CLKGEN_VOSYS_ACLK_S 73 +#define CLKGEN_CPU2VP_X2P_PCLK 74 +#define CLKGEN_X2X_CPUSYS_ACLK_S 75 +#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_CLK 76 +#define CLKGEN_IOPMP_VOSYS_DPU1_PCLK 77 +#define CLKGEN_MISC2VP_X2X_ACLK_M 78 +#define CLKGEN_WDT0_PCLK 79 +#define VOSYS_MIPIDSI0_SCANTXCLKESC 80 +#define VISYS_MIPI_CSI1_CFGCLK 81 +#define AHB2_CPUSYS_HCLK 82 +#define CLKGEN_SDIO1_HCLK 83 +#define CLKGEN_SDIO0_HCLK 84 +#define CLKGEN_CLK_OUT_3_CLK 85 +#define CLKGEN_GMAC_AXI_ACLK 86 +#define GMAC_CCLK 87 +#define CLKGEN_VIPRE_PCLK 88 +#define CLKGEN_HDMI_ISCAN_TX_CK_OUT2_CLK 89 +#define CLKGEN_MIPIDSI1_SCANTXCLKESC 90 +#define CLKGEN_VISYS_SLAVE_HCLK 91 +#define VOSYS_HDMI_ISCAN_TX_CK_OUT1_CLK 92 +#define CLKGEN_X2X_CPUSYS_ACLK_M 93 +#define CLKGEN_CPU2CFG_X2X_ACLK_S 94 +#define C910_OSC_CLK 95 +#define CLKGEN_X2H_DPU1_ACLK 96 +#define CLKGEN_I2C4_PCLK 97 +#define CLKGEN_GMAC0_ACLK 98 +#define MISC_USB3_PHY_REF_CLK 99 +#define VOSYS_MIPIDSI0_CFG_CLK 100 +#define CLKGEN_VPSYS_VDEC_CCLK 101 +#define VOSYS_MIPIDSI1_CFG_CLK 102 +#define CLKGEN_I2S_PCLK 103 +#define CLKGEN_DMAC_CPUSYS_ACLK 104 +#define VISYS_DW200_CLK_DWE 105 +#define CLKGEN_OCRAM_HCLK 106 +#define CLKGEN_EFUSE_PCLK 107 +#define CLKGEN_X2H_DPU_ACLK 108 +#define CLKGEN_IOPMP_SDIO0_ACLK 109 +#define VOSYS_DPU1_PIXELCLK 110 +#define CPU_PLL1_FOUT4 111 +#define CLKGEN_GPIO2_PCLK 112 +#define CLKGEN_GMAC1_CCLK 113 +#define CPU_PLL1_FOUTPOSTDIV 114 +#define VOSYS_HDMI_ISCAN_40M_CLK 115 +#define CLKGEN_VOSYS_X2X_ACLK_S 116 +#define CLKGEN_PERISYS_APB2_HCLK 117 +#define VOSYS_OSC_CLK_MUX_I2S_CLK_OCCBUF 118 +#define CLKGEN_HDMI_CEC_CLK 119 +#define CLKGEN_X2P_X4_VOSYS_PCLK 120 +#define CLKGEN_VOSYS_ACLK_M 121 +#define CLKGEN_EMMC_SDIO_REF_CLK 122 +#define CLKGEN_IOPMP_EMMC_ACLK 123 +#define VIDEO_PLL_FOUTVCO 124 +#define CLKGEN_HDMI_ISCAN_CKO_WORD_CLK 125 +#define CLKGEN_IOPMP_VOSYS_DPU_PCLK 126 +#define CLKGEN_AXI4_VISYS3_ACLK 127 +#define CLKGEN_VISYS_SYSREG_PCLK 128 +#define CLKGEN_MIPIDSI0_SCANTXCLKESC 129 +#define CLKGEN_HDMI_ISCAN_TX_CK_OUT1_CLK 130 +#define CLKGEN_IOPMP_EIP120SIII_ACLK 131 +#define CLKGEN_EIP120SII_ACLK 132 +#define CLKGEN_MBOX2_PCLK 133 +#define CLKGEN_AXI4_VISYS1_ACLK 134 +#define CLKGEN_UART1_PCLK 135 +#define CLK_OUT_3 136 +#define CLKGEN_UART5_SCLK 137 +#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_CLK 138 +#define CLKGEN_MBOX3_PCLK 139 +#define QSPI1_SSI_CLK 140 +#define CLKGEN_I2C1_PCLK 141 +#define CLKGEN_HDMI_I2S_CLK 142 +#define CLKGEN_AXI4_CPUSYS2_PCLK 143 +#define CLKGEN_CFG2TEE_X2H_MHCLK 144 +#define CLKGEN_C910_CPU_CLK 145 +#define VOSYS_HDMI_ISCAN_TX_CK_OUT2_CLK 146 +#define CLKGEN_HDMI_PCLK 147 +#define CLKGEN_IOPMP_EIP120SII_PCLK 148 +#define CLKGEN_MISCSYS_AXI_PCLK 149 +#define CLKGEN_EIP120SI_ACLK 150 +#define TEESYS_I1_HCLK 151 +#define PERISYS_APB_PCLK 152 +#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 153 +#define CLKGEN_TIMER0_CCLK 154 +#define CLKGEN_IOPMP_USB3_ACLK 155 +#define CLKGEN_UART2_PCLK 156 +#define CLK_OUT_4 157 +#define AXI4_CPUSYS2_ACLK 158 +#define CLKGEN_AUDIO_SUBSYS_ACLK_AP2CP 159 +#define CLKGEN_I2C3_IC_CLK 160 +#define CLKGEN_IOPMP_GPU_ACLK 161 +#define CLKGEN_TIMER1_CCLK 162 +#define VOSYS_I2S_CLK 163 +#define CLKGEN_I2C5_IC_CLK 164 +#define VOSYS_OSC_CLK_MUX_I2S_CLK 165 +#define CLKGEN_DDR_SUBSYS_ACLK_0 166 +#define CLKGEN_TIMER1_PCLK 167 +#define CLKGEN_I2C1_IC_CLK 168 +#define CLKGEN_I2S_SRC_CLK 169 +#define VISYS_DW200_CLK_VSE 170 +#define CLKGEN_MIPIDSI1_PIXCLK 171 +#define VOSYS_RTC_CLK 172 +#define CLK_OUT_1 173 +#define CLKGEN_PERISYS_APB4_HCLK 174 +#define MISC_USB3_CTRL_REF_CLK 175 +#define CLKGEN_TEE_SYSREG_PCLK 176 +#define CLKGEN_MISCSYS_AXI_ACLK 177 +#define CLKGEN_MIPIDSI1_SCANCLK 178 +#define CLKGEN_GPIO3_DBCLK 179 +#define CLKGEN_HDMI_ISCAN_40M_CLK 180 +#define CLKGEN_PERI2PERI1_APB_HCLK 181 +#define CLKGEN_GMAC0_HCLK 182 +#define CLKGEN_DDR_SUBSYS_PCLK 183 +#define VOSYS_PCLK 184 +#define CLKGEN_MIPIDSI1_SCANBYTECLK 185 +#define CLKGEN_VPSYS_G2D_ACLK 186 +#define CLKGEN_EIP150B_HCLK 187 +#define CLKGEN_UART4_SCLK 188 +#define DPU1_PLL_TEST_CLK 189 +#define CLKGEN_VOSYS_X2X_ACLK_M 190 +#define CLKGEN_IOPMP_EIP120SI_ACLK 191 +#define CLKGEN_CLK_OUT_4_CLK 192 +#define CLKGEN_GPIO0_FPCLK 193 +#define PAD_OSC_CLK 194 +#define CLKGEN_C910_BUS_CLK_NO_ICG 195 +#define CLKGEN_TIMER0_PCLK 196 +#define CLKGEN_AHB2_CPUSYS_HCLK 197 +#define EMMC_SDIO_REF_CLK 198 +#define CLKGEN_IOPMP_CHIP_DBG_PCLK 199 +#define CLKGEN_BMU_C910_PCLK 200 +#define CLKGEN_IOPMP_DPU1_ACLK 201 +#define CLKGEN_PADCTRL0_APSYS_PCLK 202 +#define MISC_SDIO1_OSC_CLK 203 +#define CLKGEN_C910_OSC_CLK 204 +#define VISYS_ISP_RY_CCLK 205 +#define CLKGEN_VPSYS_PCLK 206 +#define VISYS_MIPI_CSI0_PIXELCLK 207 +#define NPU_CCLK 208 +#define CLKGEN_AXI4_TEESYS_ACLK 209 +#define PERI2SYS_APB_PCLK 210 +#define CLKGEN_IOPMP_GMAC0_PCLK 211 +#define CLKGEN_VPSYS_G2D_PCLK 212 +#define CLKGEN_EMMC_ACLK 213 +#define CLKGEN_UART3_SCLK 214 +#define AONSYS_BUS_CLK 215 +#define DPU0_PLL_FOUT4 216 +#define VOSYS_MIPIDSI1_SCANCLK 217 +#define CLKGEN_UART4_PCLK 218 +#define CLKGEN_HDMI_ISCAN_SCL 219 +#define CLKGEN_MIPI_CSI1_PIXCLK 220 +#define CLKGEN_APSYS_CLKGEN_PCLK 221 +#define CLKGEN_GPU_TIMER_REFCLK 222 +#define GMAC_PLL_FOUT1PH0 223 +#define VOSYS_MIPIDSI1_SCANBYTECLK 224 +#define CLKGEN_GPIO3_FPCLK 225 +#define CLKGEN_SDIO1_OSC_CLK 226 +#define CLKGEN_GPIO3_PCLK 227 +#define CLKGEN_VPSYS_AXI_ACLK 228 +#define CLKGEN_HDMI_ISCAN_TX_CK_20B_CLK 229 +#define CLKGEN_VOSYSREG_PCLK 230 +#define VIDEO_PLL_TEST_CLK 231 +#define CLKGEN_MBOX1_PCLK 232 +#define CLKGEN_I2C2_IC_CLK 233 +#define VOSYS_MIPIDSI0_PLL_SCANCLK 234 +#define VOSYS_MIPIDSI1_SCANTXCLKESC 235 +#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 236 +#define CLKGEN_UART2_SCLK 237 +#define MISC_TEESYS_PCLK 238 +#define AUDIO_PLL_TEST_CLK 239 +#define CLKGEN_DPU_PIXELCLK1 240 +#define CLKGEN_IOPMP_TEEDMAC_PCLK 241 +#define CLKGEN_TOP_APB_SX_PCLK 242 +#define CLKGEN_I2C4_IC_CLK 243 +#define GMAC_PLL_TEST_CLK 244 +#define CLKGEN_HDMI_JTAG_TCLK 245 +#define VISYS_MIPI_CSI0_CFGCLK 246 +#define CLKGEN_CPU2AON_X2H_ACLK 247 +#define VOSYS_HDMI_ISCAN_TX_CK_OUT0_CLK 248 +#define QSPI_SSI_CLK 249 +#define VOSYS_DPU_CCLK 250 +#define CLKGEN_CPU2VI_X2H_MHCLK 251 +#define CLKGEN_MIPI_DSI0_REFCLK 252 +#define CLKGEN_DSPSYS_HCLK 253 +#define CLKGEN_IOPMP_AUD_PCLK 254 +#define CLKGEN_PERI2PERI1_APB_PCLK 255 +#define CFG_AXI_ACLK 256 +#define VPSYS_FCE_CCLK 257 +#define CLKGEN_HDMI_ISCAN_CLK 258 +#define CPU_PLL0_TEST_CLK 259 +#define CLKGEN_CPU2PERI_X2H_MHCLK 260 +#define VISYS_ACLK_M 261 +#define VOSYS_HDMI_JTAG_TCLK 262 +#define CLKGEN_IOPMP_AUD_ACLK 263 +#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 264 +#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_CLK 265 +#define VOSYS_MIPIDSI0_REFCLK 266 +#define CLKGEN_VISYS_ACLK_M 267 +#define VOSYS_MIPIDSI0_SCANRXCLKESC 268 +#define CLKGEN_SDIO1_ACLK 269 +#define CFG_APB_PCLK 270 +#define CLKGEN_PADCTRL1_APSYS_PCLK 271 +#define VOSYS_MIPIDSI0_SCANCLK 272 +#define CLKGEN_I2C0_IC_CLK 273 +#define CLKGEN_VPSYS_APB_PCLK 274 +#define CLKGEN_VPSYS_VENC_CCLK 275 +#define CLKGEN_AXI4_CFG_BUS_ACLK 276 +#define CLKGEN_MIPIDSI0_SCANBYTECLK 277 +#define GPIO3_DBCLK 278 +#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_CLK 279 +#define CLKGEN_UART5_PCLK 280 +#define DPU0_PLL_FOUTPOSTDIV_ICG 281 +#define CPU_PLL0_FOUT4 282 +#define CLKGEN_GPIO2_FPCLK 283 +#define CLKGEN_DPU_ACLK 284 +#define CLKGEN_AXI4_CPUSYS2_ACLK 285 +#define CLKGEN_DSPSYS_PCLK 286 +#define TEE_PLL_FOUTPOSTDIV 287 +#define TIMER_CCLK 288 +#define VOSYS_MIPIDSI1_PLL_SCANCLK 289 +#define CLKGEN_GMAC_AXI_PCLK 290 +#define CLKGEN_USB3_DRD_PCLK 291 +#define CLKGEN_AXI4_CPUSYS1_PCLK 292 +#define VOSYS_ACLK 293 +#define CLKGEN_IOPMP_EIP120SI_PCLK 294 +#define VOSYS_HDMI_ISCAN_TMDSCLKIN_CLK 295 +#define VOSYS_HDMI_ISCAN_CKO_WORD_CLK 296 +#define CLKGEN_NPUSYS_AXI_ACLK 297 +#define CLKGEN_IOPMP_SDIO0_PCLK 298 +#define CLKGEN_DW200_HCLK 299 +#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_CLK 300 +#define CLKGEN_UART0_PCLK 301 +#define CLKGEN_CLK_OUT_2_CLK 302 +#define CLKGEN_GPIO0_PCLK 303 +#define CLKGEN_EMMC_OSC_CLK 304 +#define VPSYS_APB_PCLK 305 +#define CLKGEN_HDMI_PIXCLK 306 +#define CLKGEN_IOPMP_TEEDMAC_ACLK 307 +#define AUDIO_PLL_FOUT4 308 +#define CLKGEN_MIPI_CSI2_PCLK 309 +#define CLKGEN_MIPI_DSI1_PCLK 310 +#define CLKGEN_MIPI_DSI0_CFGCLK 311 +#define VISYS_ISP0_CLK 312 +#define VISYS_ISP1_CLK 313 +#define MISC_EMMC_OSC_CLK 314 +#define DPU0_PLL_FOUTPOSTDIV 315 +#define VISYS_AHB_HCLK 316 +#define CLKGEN_IOPMP_SDIO1_ACLK 317 +#define CLKGEN_EMMC_HCLK 318 +#define I2S_CLK 319 +#define CLKGEN_CPU2PERI_X2H_ACLK 320 +#define VPSYS_AXI_ACLK 321 +#define CLKGEN_IOPMP_SDIO1_PCLK 322 +#define CLKGEN_EIP120SIII_HCLK 323 +#define CLKGEN_BMU_C910_ACLK 324 +#define CLKGEN_IOPMP_DMAC_CPUSYS_PCLK 325 +#define GPIO2_DBCLK 326 +#define CHIP_DBG_CCLK 327 +#define CLKGEN_MISCSYS_TEE_CCLK 328 +#define CLKGEN_I2C5_PCLK 329 +#define CLKGEN_X2H_CPUSYS_MHCLK 330 +#define CLKGEN_PWM_CCLK 331 +#define DPU0_PLL_TEST_CLK 332 +#define CLKGEN_VISYS_PCLK 333 +#define MISC_TEESYS_HCLK 334 +#define SPI_SSI_CLK 335 +#define CLKGEN_PWM_PCLK 336 +#define VOSYS_MIPIDSI1_SCANRXCLKESC 337 +#define QSPI0_SSI_CLK 338 +#define CLKGEN_HDMI_ISCAN_TMDSCLKIN_CLK 339 +#define CLKGEN_SPI_SSI_CLK 340 +#define VIDEO_PLL_FOUT4 341 +#define CLKGEN_IOPMP_GMAC0_ACLK 342 +#define CLKGEN_VIPRE_ACLK 343 +#define MISC_OSC_CLK_DIV24 344 +#define CLKGEN_ISP_VENC_SHAKE_PCLK 345 +#define CLKGEN_HDMI_ISCAN_TX_CK_OUT0_CLK 346 +#define CLKGEN_VPSYS_G2D_CCLK 347 +#define CLKGEN_CPU2CFG_X2X_ACLK_M 348 +#define CLKGEN_GMAC1_PCLK 349 +#define CLKGEN_MIPIDSI0_PLL_SCANCLK 350 +#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 351 +#define TEE_PLL_FOUT4 352 +#define PERISYS_AHB_HCLK 353 +#define VIDEO_PLL_FOUT1PH0 354 +#define CLKGEN_MIPIDSI0_PIXCLK 355 +#define CLKGEN_PERI_I2S_SRC_CLK_1 356 +#define CLKGEN_MIPI_CSI0_PCLK 357 +#define CLKGEN_DDR_SUBSYS_ACLK_1 358 +#define CLKGEN_GMAC0_PCLK 359 +#define CLK_OUT_2 360 +#define CLKGEN_EIP120SIII_ACLK 361 +#define AONSYS_HCLK 362 +#define CLKGEN_ISP0_CLK 363 +#define CLKGEN_C910_BROM_HCLK 364 +#define DPU1_PLL_FOUT4 365 +#define PERI_I2S_SRC_CLK 366 +#define CPU_PLL1_TEST_CLK 367 +#define CLKGEN_DDR_SUBSYS_ACLK_2 368 +#define CLKGEN_MIPIDSI0_SCANCLK 369 +#define I2C_IC_CLK 370 +#define CLKGEN_DPU_PIXELCLK0 371 +#define CLKGEN_GPIO1_DBCLK 372 +#define CLKGEN_C910_TOP_DS_PCLK 373 +#define CLKGEN_DSPSYS_ACLK_M 374 +#define CLKGEN_AON2CPU_A2X_HCLK 375 +#define VOSYS_HDMI_ISCAN_CK_REF_CLK 376 +#define CLKGEN_IOPMP_EMMC_PCLK 377 +#define NPU_CORE_CLK 378 +#define CLKGEN_IOPMP_USB3_PCLK 379 +#define VPSYS_PCLK 380 +#define VIDEO_PLL_FOUTPOSTDIV 381 +#define CLKGEN_CPU2VP_X2P_ACLK 382 +#define CLKGEN_APB_CPU2CFG_HCLK 383 +#define VOSYS_OSC_CLK_MUX_CEC_CLK_OCCBUF 384 +#define CLKGEN_GPIO1_PCLK 385 +#define CLKGEN_APSYS_SYSREG_PCLK 386 +#define CLKGEN_VISYS_HCLK 387 +#define CLKGEN_MIPI_CSI1_PCLK 388 +#define CLKGEN_AHB2_TEESYS_HCLK 389 +#define CLKGEN_DDR_SUBSYS_ACLK_4 390 +#define SYS_PLL_TEST_CLK 391 +#define VISYS_MIPI_CSI_SCANCLK 392 +#define CPU_PLL0_FOUTPOSTDIV 393 +#define CLKGEN_UART3_PCLK 394 +#define CLKGEN_X2H_CPUSYS_ACLK 395 +#define CLKGEN_MIPI_CSI1_CFG_CLK 396 +#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 397 +#define CLKGEN_MISCSYS_APB_HCLK 398 +#define CLKGEN_CPU2CFG_X2H_ACLK 399 +#define CLKGEN_MIPI_CSI2_FPCLK 400 +#define CLKGEN_ISP_RY_CCLK 401 +#define CLKGEN_X2P_VOSYS_ACLK 402 +#define CLKGEN_VIPRE_PIXELCLK 403 +#define VOSYS_GPU_TIMER_REFCLK 404 +#define VOSYS_OSC_CLK_MUX_CEC_CLK 405 +#define CLKGEN_APSYS_RSTGEN_PCLK 406 +#define VOSYS_HDMI_ISCAN_SCL 407 +#define CLKGEN_ISP_RY_HCLK 408 +#define VOSYS_OSC_CLK 409 +#define VISYS_PCLK 410 +#define CLKGEN_AXI4_VO_ACLK 411 +#define CLKGEN_MIPIDSI1_PLL_SCANCLK 412 +#define GPIO1_DBCLK 413 +#define CLKGEN_AXI4_VISYS2_ACLK 414 +#define CLKGEN_EIP120SI_HCLK 415 +#define CLKGEN_IOPMP_CHIP_DBG_ACLK 416 +#define VOSYS_HDMI_ISCAN_TX_CK_20B_CLK 417 +#define VOSYS_MIPIDSI1_REFCLK 418 +#define CLKGEN_CHIP_DBG_ACLK 419 +#define VOSYS_CFG_ACLK 420 +#define CLKGEN_VOSYS_AXI_ACLK 421 +#define CPU_BUS_DFTCLK 422 +#define VOSYS_HDMI_ISCAN_CLK 423 +#define VISYS_SLAVE_BUS_HCLK 424 +#define CLKGEN_VPSYS_VDEC_PCLK 425 +#define GMAC_PLL_FOUT4 426 +#define CLKGEN_QSPI0_PCLK 427 +#define CLKGEN_ISP1_CLK 428 +#define CLKGEN_MIPI_CSI0_FPCLK 429 +#define CLKGEN_ISP0_ACLK 430 +#define CLKGEN_CPU2VI_X2H_ACLK 431 +#define C910_CCLK 432 +#define CLKGEN_DW200_CLK_VSE 433 +#define CLKGEN_AXI4_CPUSYS1_ACLK 434 +#define CLKGEN_GPU_CFG_ACLK 435 +#define CLKGEN_GPIO1_FPCLK 436 +#define CLKGEN_SRAM_AXI_ACLK_0 437 +#define CLKGEN_I2C2_PCLK 438 +#define CLKGEN_IOPMP_GMAC1_PCLK 439 +#define CLKGEN_ISP0_S_HCLK 440 +#define GPIO0_DBCLK 441 +#define CLKGEN_AXI4_VO_CFG_ACLK 442 +#define CLKGEN_NPU_CORE_CLK 443 +#define DPU0_PLL_DIV_CLK 444 +#define VOSYS_MIPIDSI0_SCANBYTECLK 445 +#define CLKGEN_CHIP_DBG_CCLK 446 +#define CLKGEN_DMAC_CPUSYS_HCLK 447 +#define CLKGEN_IOPMP_DPU_ACLK 448 +#define CLKGEN_DDR_SUBSYS_ACLK_3 449 +#define CLK_100M 450 +#define CLKGEN_DSMART_PCLK 451 +#define CLKGEN_DW200_CLK_DWE 452 +#define VPSYS_G2D_CCLK 453 +#define CLKGEN_WDT1_PCLK 454 +#define DPU1_PLL_FOUTPOSTDIV 455 +#define CLKGEN_IOPMP_GMAC1_ACLK 456 +#define CLKGEN_VPSYS_FCE_PCLK 457 +#define CLKGEN_MIPI_CSI_SCANCLK 458 +#define CLKGEN_MIPI_CSI2_PIXCLK 459 +#define CLKGEN_I2C0_PCLK 460 +#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 461 +#define CLKGEN_HDMI_SFR_CLK 462 +#define TEE_PLL_TEST_CLK 463 +#define CLKGEN_IOPMP_DMAC_CPUSYS_ACLK 464 +#define CLKGEN_ISP_PIXELCLK 465 +#define CLKGEN_MIPI_CSI1_FPCLK 466 +#define SYS_PLL_FOUT4 467 +#define CLKGEN_AXI4_VO_PCLK 468 +#define CLKGEN_UART0_SCLK 469 +#define CLKGEN_CPU2AON_X2H_MHCLK 470 +#define VISYS_MIPI_CSI_SCANBYTECLK 471 +#define UART_SCLK 472 +#define CLKGEN_IOPMP_AON_ACLK 473 +#define CLKGEN_VPSYS_VDEC_ACLK 474 +#define CLKGEN_GMAC1_HCLK 475 +#define CLKGEN_ISP_VENC_SHAKE_ACLK 476 +#define TEESYS_HCLK 477 +#define PWM_CCLK 478 +#define CLKGEN_GPIO0_DBCLK 479 +#define CLKGEN_SDIO0_OSC_CLK 480 +#define CLKGEN_GMAC1_ACLK 481 +#define VPSYS_ACLK 482 + +#define AHB2_CPUSYS_HCLK_OUT_DIV 483 +#define APB3_CPUSYS_PCLK_DIV 484 +#define CFG_AXI_ACLK_OUT_DIV 485 +#define PERISYS_AHB_HCLK_OUT_DIV 486 +#define CLK_OUT_1_OUT_DIV 487 +#define CLK_OUT_2_OUT_DIV 488 +#define CLK_OUT_3_OUT_DIV 489 +#define CLK_OUT_4_OUT_DIV 490 +#define NPU_CCLK_OUT_DIV 491 +#define CFG_APB_PCLK_OUT_DIV 492 +#define CPU_PLL0_BYPASS 493 +#define CPU_PLL1_BYPASS 494 +#define GMAC_PLL_BYPASS 495 +#define VIDEO_PLL_BYPASS 496 +#define TEE_PLL_BYPASS 497 +#define DPU0_PLL_BYPASS 498 +#define DPU1_PLL_BYPASS 499 + +#define CLK_DUMMY 500 +#define OSC_32K 501 +#define OSC_24M 502 +#define RC_24M 503 + +#define CLK_END 504 + +#endif diff --git a/include/dt-bindings/clock/light-mpw-clock.h b/include/dt-bindings/clock/light-mpw-clock.h new file mode 100644 index 00000000000000..46c2a052a9d20d --- /dev/null +++ b/include/dt-bindings/clock/light-mpw-clock.h @@ -0,0 +1,222 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#ifndef __DT_BINDINGS_CLOCK_LIGHT_H +#define __DT_BINDINGS_CLOCK_LIGHT_H + +#define LIGHT_CLK_DUMMY 0 +#define LIGHT_CLK_32K 1 +#define LIGHT_CLK_24M 2 +#define LIGHT_RC_24M 3 + +#define LIGHT_VIDEO_PLL_FOUTVCO 4 +#define LIGHT_VIDEO_PLL_FOUTPOSTDIV 5 +#define LIGHT_VIDEO_PLL_FOUT4 6 +#define LIGHT_VIDEO_PLL_BYPASS 7 + +#define LIGHT_GMAC_PLL_FOUTVCO 8 +#define LIGHT_GMAC_PLL_FOUTPOSTDIV 9 +#define LIGHT_GMAC_PLL_FOUT1PH0 10 +#define LIGHT_GMAC_PLL_FOUT4 11 +#define LIGHT_GMAC_PLL_BYPASS 12 + +#define LIGHT_AUDIO_PLL_FOUTVCO 13 +#define LIGHT_AUDIO_PLL_FOUTPOSTDIV 14 +#define LIGHT_AUDIO_PLL_FOUT3 15 +#define LIGHT_AUDIO_PLL_BYPASS 16 + +#define LIGHT_SYS_PLL_FOUTVCO 17 +#define LIGHT_SYS_PLL_FOUTPOSTDIV 18 +#define LIGHT_SYS_PLL_FOUT4 19 +#define LIGHT_SYS_PLL_BYPASS 20 + +#define LIGHT_CPU_PLL0_FOUTVCO 21 +#define LIGHT_CPU_PLL0_FOUTPOSTDIV 22 +#define LIGHT_CPU_PLL0_FOUT4 23 +#define LIGHT_CPU_PLL0_BYPASS 24 + +#define LIGHT_CPU_PLL1_FOUTVCO 25 +#define LIGHT_CPU_PLL1_FOUTPOSTDIV 26 +#define LIGHT_CPU_PLL1_FOUT4 27 +#define LIGHT_CPU_PLL1_BYPASS 28 + +#define LIGHT_DDR_PLL_FOUTVCO 29 +#define LIGHT_DDR_PLL_FOUTPOSTDIV 30 +#define LIGHT_DDR_PLL_FOUT4 31 +#define LIGHT_DDR_PLL_BYPASS 32 + +#define LIGHT_AONSYS_CLK_SWITCH_0 33 +#define LIGHT_AONSYS_CLK_SWITCH_1 34 +#define LIGHT_AONSYS_CLK 35 +#define LIGHT_SHARE_SRAM_CLK 36 +#define LIGHT_CLKGEN_RTC_PCLK 37 +#define LIGHT_CLKGEN_AOGPIO_PCLK 38 +#define LIGHT_CLKGEN_AOI2C_PCLK 39 +#define LIGHT_CLKGEN_PVTC_PCLK 40 +#define LIGHT_CLKGEN_AOAHB_HCLK 41 +#define LIGHT_CLKGEN_AOSRAM_HCLK 42 +#define LIGHT_CLKGEN_AOAPB_HCLK 43 +#define LIGHT_CLKGEN_AOPAD_PCLK 44 +#define LIGHT_CLKGEN_AOTIMER_PCLK 45 +#define LIGHT_CLKGEN_AOTIMER_CCLK 46 +#define LIGHT_CLKGEN_SRAM_AXI_ACLK 47 +#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S 48 +#define LIGHT_CLKGEN_AOGPIO_DBCLK 49 + +#define LIGHT_GMAC_CORECLK 50 +#define LIGHT_OSC_CLK_DIV24 51 +#define LIGHT_GMAC_PLL_FOUTVCO_DIV5 52 +#define LIGHT_C910_CCLK_I0 53 +#define LIGHT_C910_CCLK 54 +#define LIGHT_CPUSYS_AHB_HCLK 55 +#define LIGHT_CPUSYS_CFG_AXI_ACLK 56 +#define LIGHT_PERISYS_AHB_HCLK 57 +#define LIGHT_CLK_OUT_1 58 +#define LIGHT_CLK_OUT_2 59 +#define LIGHT_CLK_OUT_3 60 +#define LIGHT_CLK_OUT_4 61 +#define LIGHT_CPUSYS_AHB_HCLK_DIV 62 +#define LIGHT_APB3_CPUSYS_PCLK 63 +#define LIGHT_CPUSYS_SUB_AXI_ACLK 64 +#define LIGHT_CPUSYS_CFG_AXI_ACLK_DIV 65 +#define LIGHT_TEESYS_HCLK 66 +#define LIGHT_DMAC_1_CLK 67 +#define LIGHT_DMAC_2_CLK 68 +#define LIGHT_DMAC_3_CLK 69 +#define LIGHT_AXI_PORT4_CLK 70 +#define LIGHT_PERISYS_AHB_HCLK_DIV 71 +#define LIGHT_PERISYS_APB_PCLK 72 +#define LIGHT_CLK_OUT_1_DIV 73 +#define LIGHT_CLK_OUT_2_DIV 74 +#define LIGHT_CLK_OUT_3_DIV 75 +#define LIGHT_CLK_OUT_4_DIV 76 +#define LIGHT_CLKGEN_PERISYS_AXI_ACLK 77 +#define LIGHT_CLKGEN_PERISYS_AHB_HCLK 78 +#define LIGHT_CLKGEN_PERISYS_APB1_HCLK 79 +#define LIGHT_CLKGEN_PERISYS_APB2_HCLK 80 +#define LIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK 81 +#define LIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK 82 +#define LIGHT_CLKGEN_USB3_DRD_SPDCLK 83 +#define LIGHT_CLKGEN_USB3_DRD_ACLK 84 +#define LIGHT_CLKGEN_EMMC1_X2X_ACLK 85 +#define LIGHT_CLKGEN_EMMC0_X2X_ACLK 86 +#define LIGHT_CLKGEN_EMMC0_HCLK 87 +#define LIGHT_CLKGEN_EMMC1_HCLK 88 +#define LIGHT_CLKGEN_GMAC_ACLK 89 +#define LIGHT_CLKGEN_PWM_PCLK 90 +#define LIGHT_CLKGEN_QSPI0_PCLK 91 +#define LIGHT_CLKGEN_QSPI1_PCLK 92 +#define LIGHT_CLKGEN_SPI_PCLK 93 +#define LIGHT_CLKGEN_UART0_PCLK 94 +#define LIGHT_CLKGEN_UART1_PCLK 95 +#define LIGHT_CLKGEN_UART2_PCLK 96 +#define LIGHT_CLKGEN_UART3_PCLK 97 +#define LIGHT_CLKGEN_UART4_PCLK 98 +#define LIGHT_CLKGEN_UART5_PCLK 99 +#define LIGHT_CLKGEN_GPIO0_PCLK 100 +#define LIGHT_CLKGEN_GPIO1_PCLK 101 +#define LIGHT_CLKGEN_GPIO2_PCLK 102 +#define LIGHT_CLKGEN_I2C0_IC_CLK 103 +#define LIGHT_CLKGEN_I2C1_IC_CLK 104 +#define LIGHT_CLKGEN_I2C2_IC_CLK 105 +#define LIGHT_CLKGEN_I2C3_IC_CLK 106 +#define LIGHT_CLKGEN_I2C4_IC_CLK 107 +#define LIGHT_CLKGEN_I2C5_IC_CLK 108 +#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_M 109 +#define LIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK 110 +#define LIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK 111 +#define LIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK 112 +#define LIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK 113 +#define LIGHT_CLKGEN_APB_CPU2FG_HCLK 114 +#define LIGHT_CLKGEN_AON2CPU_A2X_ACLK 115 +#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_M 116 +#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M 117 +#define LIGHT_CLKGEN_AXI4_CPUSYS2_ACLK 118 +#define LIGHT_CLKGEN_X2X_CPUSYS_ACLK_M 119 +#define LIGHT_CLKGEN_CHIP_DBG_ACLK 120 +#define LIGHT_CLKGEN_AXI4_CFG_BUS_ACLK 121 +#define LIGHT_CLKGEN_X2H_CPUSYS_ACLK 122 +#define LIGHT_CLKGEN_CPU2TEE_X2H_ACLK 123 +#define LIGHT_CLKGEN_CPU2AON_X2H_ACLK 124 +#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK 125 +#define LIGHT_CLKGEN_CPU2PERI_X2H_MHCLK 126 +#define LIGHT_CLKGEN_AHB2_CPUSYS_HCLK 127 +#define LIGHT_CLKGEN_APB3_CPUSYS_HCLK 128 +#define LIGHT_CLKGEN_C910_BROM_HCLK 129 +#define LIGHT_CLKGEN_DMAC_ACLK 130 +#define LIGHT_CLKGEN_MBOX0_PCLK 131 +#define LIGHT_CLKGEN_MBOX1_PCLK 132 +#define LIGHT_CLKGEN_MBOX2_PCLK 133 +#define LIGHT_CLKGEN_MBOX3_PCLK 134 +#define LIGHT_CLKGEN_WDT0_PCLK 135 +#define LIGHT_CLKGEN_WDT1_PCLK 136 +#define LIGHT_CLKGEN_TIMER0_CCLK 137 +#define LIGHT_CLKGEN_TIMER1_CCLK 138 +#define LIGHT_CLKGEN_TRNG_RB_HCLK 139 +#define LIGHT_CLKGEN_ADC_PCLK 140 +#define LIGHT_CLKGEN_AXI_ACLK_4 141 +#define LIGHT_CLKGEN_AXI_ACLK_3 142 +#define LIGHT_CLKGEN_AXI_ACLK_2 143 +#define LIGHT_CLKGEN_AXI_ACLK_1 145 +#define LIGHT_CLKGEN_AXI_ACLK_0 146 +#define LIGHT_CLKGEN_DMAC_1_ACLK 147 +#define LIGHT_CLKGEN_DMAC_2_ACLK 148 +#define LIGHT_CLKGEN_DMAC_3_ACLK 149 +#define LIGHT_CLKGEN_SRAM_AXI_PCLK 150 +#define LIGHT_CLKGEN_AHB2_TEESYS_HCLK 151 +#define LIGHT_CLKGEN_EFUSE_MPW_PCLK 152 +#define LIGHT_CLKGEN_CLK_OUT_4_CLK 153 +#define LIGHT_CLKGEN_CLK_OUT_3_CLK 154 +#define LIGHT_CLKGEN_CLK_OUT_2_CLK 155 +#define LIGHT_CLKGEN_CLK_OUT_1_CLK 156 +#define LIGHT_CLKGEN_DDR_APB_PCLK 157 +#define LIGHT_CLKGEN_PADCTRL_APSYS_PCLK 158 +#define LIGHT_CLKGEN_CHIP_DBG_CCLK 159 +#define LIGHT_CHIP_DBG_CCLK 160 +#define LIGHT_AXI_ACLK 161 + +#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_S 162 +#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK_S 163 +#define LIGHT_CLKGEN_AON2CPU_A2X_HCLK 164 +#define LIGHT_CLKGEN_DMAC_HCLK 165 +#define LIGHT_CLKGEN_X2H_CPUSYS_MHCLK 166 +#define LIGHT_CLKGEN_CPU2TEE_X2H_MHCLK 167 +#define LIGHT_CLKGEN_CPU2AON_X2H_MHCLK 168 +#define LIGHT_AXI_HCLK 169 +#define LIGHT_CLKGEN_CPU2CFG_X2H_MHCLK 170 +#define LIGHT_CLKGEN_TIMER0_PCLK 171 +#define LIGHT_CLKGEN_TIMER1_PCLK 172 +#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_S 173 +#define LIGHT_CLKGEN_USB3_DRD_PCLK 174 +#define LIGHT_CLKGEN_GMAC_HCLK 175 +#define LIGHT_CLKGEN_GMAC_PCLK 176 +#define LIGHT_CLKGEN_GMAC_CCLK 177 +#define LIGHT_CLKGEN_EMMC0_ACLK 178 +#define LIGHT_CLKGEN_EMMC0_REF_CLK 179 +#define LIGHT_CLKGEN_EMMC0_OSC_CLK 180 +#define LIGHT_CLKGEN_EMMC1_ACLK 181 +#define LIGHT_CLKGEN_EMMC1_REF_CLK 182 +#define LIGHT_CLKGEN_EMMC1_OSC_CLK 183 +#define LIGHT_CLKGEN_PWM_CCLK 184 +#define LIGHT_CLKGEN_QSPI0_SSI_CLK 185 +#define LIGHT_CLKGEN_QSPI1_SSI_CLK 186 +#define LIGHT_CLKGEN_SPI_SSI_CLK 187 +#define LIGHT_CLKGEN_GPIO0_DBCLK 188 +#define LIGHT_CLKGEN_GPIO1_DBCLK 189 +#define LIGHT_CLKGEN_GPIO2_DBCLK 190 +#define LIGHT_CLKGEN_DMAC_1_HCLK 191 +#define LIGHT_CLKGEN_DMAC_2_HCLK 192 +#define LIGHT_CLKGEN_DMAC_3_HCLK 193 +#define LIGHT_EMMC_CLK_DIV 194 +#define LIGHT_EMMC0_OSC_CLK 195 +#define LIGHT_EMMC1_OSC_CLK 196 +#define LIGHT_PWM_CCLK 197 +#define LIGHT_USB3_PHY_REF_CLK 198 +#define LIGHT_SPI_CLK 199 +#define LIGHT_GPIO_DBCLK 200 +#define LIGHT_X2H_HCLK 201 + +#define LIGHT_CLK_END 202 +#endif diff --git a/include/dt-bindings/clock/light-visys.h b/include/dt-bindings/clock/light-visys.h new file mode 100644 index 00000000000000..53fed0bfb62477 --- /dev/null +++ b/include/dt-bindings/clock/light-visys.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#ifndef _LIGHT_VISYS_H +#define _LIGHT_VISYS_H + +#define LIGHT_CLKGEN_VISYS_ACLK 0 +#define LIGHT_CLKGEN_DW200_ACLK 1 +#define LIGHT_CLKGEN_AXI4_VISYS1_ACLK 2 +#define LIGHT_CLKGEN_AXI4_VISYS2_ACLK 3 +#define LIGHT_CLKGEN_AXI4_VISYS3_ACLK 4 +#define LIGHT_CLKGEN_ISP0_ACLK 5 +#define LIGHT_CLKGEN_ISP_RY_ACLK 6 +#define LIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK 7 +#define LIGHT_CLKGEN_VIPRE_ACLK 8 +#define LIGHT_CLKGEN_VISYS_SLAVE_HCLK 9 +#define LIGHT_CLKGEN_ISP0_S_HCLK 10 +#define LIGHT_CLKGEN_DW200_HCLK 11 +#define LIGHT_CLKGEN_ISP_RY_HCLK 12 +#define LIGHT_CLKGEN_MIPI_CSI0_PCLK 13 +#define LIGHT_CLKGEN_MIPI_CSI0_FPCLK 14 +#define LIGHT_CLKGEN_MIPI_CSI1_PCLK 15 +#define LIGHT_CLKGEN_MIPI_CSI1_FPCLK 16 +#define LIGHT_CLKGEN_MIPI_CSI2_PCLK 17 +#define LIGHT_CLKGEN_MIPI_CSI2_FPCLK 18 +#define LIGHT_CLKGEN_VIPRE_PCLK 19 +#define LIGHT_CLKGEN_VISYS_PCLK 20 +#define LIGHT_CLKGEN_VISYS_SYSREG_PCLK 21 +#define LIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK 22 +#define LIGHT_CLKGEN_MIPI_CSI0_PIXCLK 23 +#define LIGHT_CLKGEN_MIPI_CSI1_PIXCLK 24 +#define LIGHT_CLKGEN_MIPI_CSI2_PIXCLK 25 +#define LIGHT_CLKGEN_VIPRE_PIXELCLK 26 +#define LIGHT_CLKGEN_ISP_PIXELCLK 27 +#define LIGHT_CLKGEN_MIPI_CSI0_CFG_CLK 28 +#define LIGHT_CLKGEN_MIPI_CSI1_CFG_CLK 29 +#define LIGHT_CLKGEN_MIPI_CSI2_CFG_CLK 30 +#define LIGHT_CLKGEN_DW200_CLK_VSE 31 +#define LIGHT_CLKGEN_DW200_CLK_DWE 32 +#define LIGHT_CLKGEN_ISP0_CLK 33 +#define LIGHT_CLKGEN_ISP1_CLK 34 +#define LIGHT_CLKGEN_ISP_RY_CCLK 35 +#define LIGHT_CLKGEN_MIPI_CSI_SCANBYTECLK 36 +#define LIGHT_CLKGEN_MIPI_CSI_SCANCLK 37 +#define LIGHT_CLKGEN_ISP1_PIXELCLK 38 +#define LIGHT_CLKGEN_ISP0_PIXELCLK 39 +#define LIGHT_CLKGEN_ISP1_HCLK 40 +#define LIGHT_CLKGEN_ISP0_HCLK 41 +#define LIGHT_CLKGEN_ISP1_ACLK 42 +#define LIGHT_CLKGEN_VISYS_CLK_END 43 + +#endif diff --git a/include/dt-bindings/clock/light-vosys.h b/include/dt-bindings/clock/light-vosys.h new file mode 100644 index 00000000000000..dbdd7fa7016ba5 --- /dev/null +++ b/include/dt-bindings/clock/light-vosys.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#ifndef LIGHT_VOSYS_H +#define LIGHT_VOSYS_H + +#define LIGHT_CLKGEN_AXI4_VO_PCLK 0 +#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK 1 +#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK 2 +#define LIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK 3 +#define LIGHT_CLKGEN_HDMI_PCLK 4 +#define LIGHT_CLKGEN_MIPIDSI0_PCLK 5 +#define LIGHT_CLKGEN_MIPIDSI1_PCLK 6 +#define LIGHT_CLKGEN_AXI4_VO_ACLK 7 +#define LIGHT_CLKGEN_IOPMP_GPU_ACLK 8 +#define LIGHT_CLKGEN_IOPMP_DPU_ACLK 9 +#define LIGHT_CLKGEN_IOPMP_DPU1_ACLK 10 +#define LIGHT_CLKGEN_X2H_DPU_ACLK 11 +#define LIGHT_CLKGEN_X2H_DPU1_ACLK 12 +#define LIGHT_CLKGEN_MIPIDSI0_PIXCLK 13 +#define LIGHT_CLKGEN_HDMI_PIXCLK 14 +#define LIGHT_CLKGEN_MIPIDSI1_PIXCLK 15 +#define LIGHT_CLKGEN_HDMI_SFR_CLK 16 +#define LIGHT_CLKGEN_HDMI_CEC_CLK 17 +#define LIGHT_CLKGEN_HDMI_I2S_CLK 18 +#define LIGHT_CLKGEN_MIPIDSI0_CFG_CLK 19 +#define LIGHT_CLKGEN_MIPIDSI1_CFG_CLK 20 +#define LIGHT_CLKGEN_MIPIDSI0_REFCLK 21 +#define LIGHT_CLKGEN_MIPIDSI1_REFCLK 22 +#define LIGHT_CLKGEN_GPU_CORE_CLK 23 +#define LIGHT_CLKGEN_GPU_CFG_ACLK 24 +#define LIGHT_CLKGEN_DPU_HCLK 25 +#define LIGHT_CLKGEN_DPU_ACLK 26 +#define LIGHT_CLKGEN_DPU_CCLK 27 +#define LIGHT_CLKGEN_DPU_PIXCLK0 28 +#define LIGHT_CLKGEN_DPU_PIXCLK1 29 +#define LIGHT_CLKGEN_VOSYS_CLK_END 30 + +#endif diff --git a/include/dt-bindings/clock/light-vpsys.h b/include/dt-bindings/clock/light-vpsys.h new file mode 100644 index 00000000000000..188aaa6cc43501 --- /dev/null +++ b/include/dt-bindings/clock/light-vpsys.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#ifndef _LIGHT_VPSYS_H +#define _LIGHT_VPSYS_H + +#define LIGHT_VPSYS_G2D_PCLK 0 +#define LIGHT_VPSYS_G2D_ACLK 1 +#define LIGHT_VPSYS_G2D_CCLK 2 +#define LIGHT_VPSYS_FCE_PCLK 3 +#define LIGHT_VPSYS_FCE_ACLK 4 +#define LIGHT_VPSYS_VDEC_PCLK 5 +#define LIGHT_VPSYS_VDEC_ACLK 6 +#define LIGHT_VPSYS_VDEC_CCLK 7 +#define LIGHT_VPSYS_AXI_ACLK 8 +#define LIGHT_VPSYS_VENC_CCLK 9 +#define LIGHT_VPSYS_VENC_PCLK 10 +#define LIGHT_VPSYS_VENC_ACLK 11 +#define LIGHT_VPSYS_CLK_END 12 + +#endif + diff --git a/include/dt-bindings/firmware/thead/rsrc.h b/include/dt-bindings/firmware/thead/rsrc.h new file mode 100644 index 00000000000000..8cee0fcaeb749e --- /dev/null +++ b/include/dt-bindings/firmware/thead/rsrc.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 Alibaba Group Holding Limited. + */ + +#ifndef __DT_BINDINGS_RSCRC_LIGHT_H +#define __DT_BINDINGS_RSCRC_LIGHT_H + +#define LIGHT_AON_AUDIO_PD 0 +#define LIGHT_AON_VDEC_PD 1 +#define LIGHT_AON_NPU_PD 2 +#define LIGHT_AON_VENC_PD 3 +#define LIGHT_AON_GPU_PD 4 +#define LIGHT_AON_DSP0_PD 5 +#define LIGHT_AON_DSP1_PD 6 + +#endif diff --git a/include/linux/firmware/thead/ipc.h b/include/linux/firmware/thead/ipc.h new file mode 100644 index 00000000000000..dd23f320173935 --- /dev/null +++ b/include/linux/firmware/thead/ipc.h @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#ifndef _SC_IPC_H +#define _SC_IPC_H + +#include +#include + +#define AON_RPC_MSG_MAGIC (0xef) +#define LIGHT_AON_RPC_VERSION 1 +#define LIGHT_AON_RPC_MSG_NUM 7 + +struct light_aon_ipc; + +enum light_aon_rpc_svc { + LIGHT_AON_RPC_SVC_UNKNOWN = 0, + LIGHT_AON_RPC_SVC_RETURN = 1, + LIGHT_AON_RPC_SVC_PM = 2, + LIGHT_AON_RPC_SVC_MISC = 3, + LIGHT_AON_RPC_SVC_AVFS = 4, +}; + +enum light_aon_misc_func { + LIGHT_AON_MISC_FUNC_UNKNOWN = 0, + LIGHT_AON_MISC_FUNC_SET_CONTROL = 1, + LIGHT_AON_MISC_FUNC_GET_CONTROL = 2, + LIGHT_AON_MISC_FUNC_WDG_START = 3, + LIGHT_AON_MISC_FUNC_WDG_STOP = 4, + LIGHT_AON_MISC_FUNC_WDG_PING = 5, + LIGHT_AON_MISC_FUNC_WDG_TIMEOUTSET = 6, + LIGHT_AON_MISC_FUNC_WDG_RESTART = 7, + LIGHT_AON_MISC_FUNC_WDG_GET_STATE = 8, + LIGHT_AON_MISC_FUNC_WDG_POWER_OFF = 9, + LIGHT_AON_MISC_FUNC_AON_WDT_ON = 10, + LIGHT_AON_MISC_FUNC_AON_WDT_OFF = 11, + LIGHT_AON_MISC_FUNC_AON_RESERVE_MEM = 12, +}; + +enum light_aon_pm_func { + LIGHT_AON_PM_FUNC_UNKNOWN = 0, + LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1, + LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2, + LIGHT_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3, + LIGHT_AON_PM_FUNC_PWR_SET = 4, + LIGHT_AON_PM_FUNC_PWR_GET = 5, +}; + +struct light_aon_rpc_msg_hdr { + uint8_t ver; ///< version of msg hdr + uint8_t size; ///< msg size ,uinit in bytes,the size includes rpc msg header self. + uint8_t svc; ///< rpc main service id + uint8_t func; ///< rpc sub func id of specific service, sent by caller +} __packed __aligned(4); + +/* + * Defines for SC PM Power Mode + */ +#define LIGHT_AON_PM_PW_MODE_OFF 0 /* Power off */ +#define LIGHT_AON_PM_PW_MODE_STBY 1 /* Power in standby */ +#define LIGHT_AON_PM_PW_MODE_LP 2 /* Power in low-power */ +#define LIGHT_AON_PM_PW_MODE_ON 3 /* Power on */ + +int light_aon_call_rpc(struct light_aon_ipc *ipc, void *msg, bool have_resp); +int light_aon_get_handle(struct light_aon_ipc **ipc); +int light_aon_misc_set_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 val); +int light_aon_misc_get_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 *val); +#endif /* _SC_IPC_H */ From a507558c212ad7a491c26be33063f271176050aa Mon Sep 17 00:00:00 2001 From: ixgbe01 Date: Mon, 27 Nov 2023 11:27:25 +0800 Subject: [PATCH 46/52] fix compile th1520-beaglev-ahead error --- arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts index 89163615d2e6e3..36f47436d39c1a 100644 --- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts +++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts @@ -37,7 +37,7 @@ }; }; -&osc { +&osc_24m { clock-frequency = <24000000>; }; From 8945a81652ce6d71a3f583d90039f349796b6ae5 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Wed, 29 Nov 2023 04:13:05 +0800 Subject: [PATCH 47/52] [NFU] configs: enable th1520 driver & enable cpu-freq Signed-off-by: Han Gao --- arch/riscv/configs/revyos_defconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/riscv/configs/revyos_defconfig b/arch/riscv/configs/revyos_defconfig index 5638a0bff9413c..87b4fa6e137468 100644 --- a/arch/riscv/configs/revyos_defconfig +++ b/arch/riscv/configs/revyos_defconfig @@ -41,8 +41,6 @@ CONFIG_KEXEC=y CONFIG_ARCH_THEAD=y CONFIG_SMP=y CONFIG_NUMA=y -# CONFIG_RISCV_ISA_V is not set -# CONFIG_RISCV_ISA_ZBB is not set CONFIG_RISCV_SBI_V01=y # CONFIG_RISCV_BOOT_SPINWAIT is not set CONFIG_PM_DEBUG=y @@ -60,6 +58,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPUFREQ_DT=m CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_RISV_THEAD_LIGHT_CPUFREQ=y CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y # CONFIG_COMPAT_32BIT_TIME is not set @@ -595,6 +594,7 @@ CONFIG_GOOGLE_VPD=m CONFIG_EFI_BOOTLOADER_CONTROL=m CONFIG_EFI_CAPSULE_LOADER=m CONFIG_RESET_ATTACK_MITIGATION=y +CONFIG_LIGHT_AON_PD=y CONFIG_GNSS=m CONFIG_GNSS_SIRF_SERIAL=m CONFIG_GNSS_UBX_SERIAL=m @@ -2034,6 +2034,7 @@ CONFIG_RTL8723BS=m CONFIG_R8712U=m CONFIG_QLGE=m CONFIG_GOLDFISH=y +CONFIG_CLK_LIGHT_FM=y CONFIG_MAILBOX=y CONFIG_SOUNDWIRE=m CONFIG_SOUNDWIRE_QCOM=m From 1532bf4f5f513cb5b0c26784a300b8b7ab990c9c Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sat, 2 Dec 2023 19:18:21 +0800 Subject: [PATCH 48/52] riscv: introduce RISCV_EFFICIENT_UNALIGNED_ACCESS Some riscv implementations such as T-HEAD's C906, C908, C910 and C920 supports efficient unaligned access, for performance reason we want to enable HAVE_EFFICIENT_UNALIGNED_ACCESS on these platforms. To avoid performance regressions on other non efficient unaligned access platforms, HAVE_EFFICIENT_UNALIGNED_ACCESS can't be globaly selected. To solve this problem, runtime code patching based on the detected speed is a good solution. But that's not easy, it involves lots of work to modify vairous subsystems such as net, mm, lib and so on. This can be done step by step. Now let's introduce RISCV_EFFICIENT_UNALIGNED_ACCESS which depends on NONPORTABLE, if users know during config time that the kernel will be only run on those efficient unaligned access hw platforms, they can enable it. Obviously, generic unified kernel Image should enable it. Signed-off-by: Jisheng Zhang --- arch/riscv/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 469d8ca8618344..fca0ef8cd7f7ab 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -639,6 +639,18 @@ config THREAD_SIZE_ORDER Specify the Pages of thread stack size (from 4KB to 64KB), which also affects irq stack size, which is equal to thread stack size. +config RISCV_EFFICIENT_UNALIGNED_ACCESS + bool "Use unaligned access for some functions" + depends on NONPORTABLE + select HAVE_EFFICIENT_UNALIGNED_ACCESS + default n + help + Say Y here if you want the kernel only run on hardware platforms which + support efficient unaligned access, then unaligned access will be used + in some functions for optimized performance. + + If unsure what to do here, say N. + endmenu # "Platform type" menu "Kernel features" From 1f1f7417e7e8b04eaee2b9b8710315589c8a1ec4 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sat, 2 Dec 2023 19:18:22 +0800 Subject: [PATCH 49/52] riscv: select DCACHE_WORD_ACCESS for efficient unaligned access HW DCACHE_WORD_ACCESS uses the word-at-a-time API for optimised string comparisons in the vfs layer. This patch implements support for load_unaligned_zeropad in much the same way as has been done for arm64. Here is the test program and step: $ cat tt.c #include #include #include #define ITERATIONS 1000000 #define PATH "123456781234567812345678123456781" int main(void) { unsigned long i; struct stat buf; for (i = 0; i < ITERATIONS; i++) stat(PATH, &buf); return 0; } $ gcc -O2 tt.c $ touch 123456781234567812345678123456781 $ time ./a.out Per my test on T-HEAD C910 platforms, the above test performance is improved by about 7.5%. Signed-off-by: Jisheng Zhang --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/asm-extable.h | 15 ++++++++++++ arch/riscv/include/asm/word-at-a-time.h | 23 ++++++++++++++++++ arch/riscv/mm/extable.c | 31 +++++++++++++++++++++++++ 4 files changed, 70 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index fca0ef8cd7f7ab..d604111f52a87e 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -642,6 +642,7 @@ config THREAD_SIZE_ORDER config RISCV_EFFICIENT_UNALIGNED_ACCESS bool "Use unaligned access for some functions" depends on NONPORTABLE + select DCACHE_WORD_ACCESS if MMU select HAVE_EFFICIENT_UNALIGNED_ACCESS default n help diff --git a/arch/riscv/include/asm/asm-extable.h b/arch/riscv/include/asm/asm-extable.h index 00a96e7a966445..0c8bfd54fc4e05 100644 --- a/arch/riscv/include/asm/asm-extable.h +++ b/arch/riscv/include/asm/asm-extable.h @@ -6,6 +6,7 @@ #define EX_TYPE_FIXUP 1 #define EX_TYPE_BPF 2 #define EX_TYPE_UACCESS_ERR_ZERO 3 +#define EX_TYPE_LOAD_UNALIGNED_ZEROPAD 4 #ifdef CONFIG_MMU @@ -47,6 +48,11 @@ #define EX_DATA_REG_ZERO_SHIFT 5 #define EX_DATA_REG_ZERO GENMASK(9, 5) +#define EX_DATA_REG_DATA_SHIFT 0 +#define EX_DATA_REG_DATA GENMASK(4, 0) +#define EX_DATA_REG_ADDR_SHIFT 5 +#define EX_DATA_REG_ADDR GENMASK(9, 5) + #define EX_DATA_REG(reg, gpr) \ "((.L__gpr_num_" #gpr ") << " __stringify(EX_DATA_REG_##reg##_SHIFT) ")" @@ -62,6 +68,15 @@ #define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err) \ _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero) +#define _ASM_EXTABLE_LOAD_UNALIGNED_ZEROPAD(insn, fixup, data, addr) \ + __DEFINE_ASM_GPR_NUMS \ + __ASM_EXTABLE_RAW(#insn, #fixup, \ + __stringify(EX_TYPE_LOAD_UNALIGNED_ZEROPAD), \ + "(" \ + EX_DATA_REG(DATA, data) " | " \ + EX_DATA_REG(ADDR, addr) \ + ")") + #endif /* __ASSEMBLY__ */ #else /* CONFIG_MMU */ diff --git a/arch/riscv/include/asm/word-at-a-time.h b/arch/riscv/include/asm/word-at-a-time.h index 7c086ac6ecd4a8..5a3865ac36230c 100644 --- a/arch/riscv/include/asm/word-at-a-time.h +++ b/arch/riscv/include/asm/word-at-a-time.h @@ -9,6 +9,7 @@ #define _ASM_RISCV_WORD_AT_A_TIME_H +#include #include struct word_at_a_time { @@ -45,4 +46,26 @@ static inline unsigned long find_zero(unsigned long mask) /* The mask we created is directly usable as a bytemask */ #define zero_bytemask(mask) (mask) +/* + * Load an unaligned word from kernel space. + * + * In the (very unlikely) case of the word being a page-crosser + * and the next page not being mapped, take the exception and + * return zeroes in the non-existing part. + */ +static inline unsigned long load_unaligned_zeropad(const void *addr) +{ + unsigned long ret; + + /* Load word from unaligned pointer addr */ + asm( + "1: " REG_L " %0, %2\n" + "2:\n" + _ASM_EXTABLE_LOAD_UNALIGNED_ZEROPAD(1b, 2b, %0, %1) + : "=&r" (ret) + : "r" (addr), "m" (*(unsigned long *)addr)); + + return ret; +} + #endif /* _ASM_RISCV_WORD_AT_A_TIME_H */ diff --git a/arch/riscv/mm/extable.c b/arch/riscv/mm/extable.c index 35484d830fd6d7..dd1530af3ef15b 100644 --- a/arch/riscv/mm/extable.c +++ b/arch/riscv/mm/extable.c @@ -27,6 +27,14 @@ static bool ex_handler_fixup(const struct exception_table_entry *ex, return true; } +static inline unsigned long regs_get_gpr(struct pt_regs *regs, unsigned int offset) +{ + if (unlikely(!offset || offset > MAX_REG_OFFSET)) + return 0; + + return *(unsigned long *)((unsigned long)regs + offset); +} + static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset, unsigned long val) { @@ -50,6 +58,27 @@ static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex, return true; } +static bool +ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex, + struct pt_regs *regs) +{ + int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data); + int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data); + unsigned long data, addr, offset; + + addr = regs_get_gpr(regs, reg_addr * sizeof(unsigned long)); + + offset = addr & 0x7UL; + addr &= ~0x7UL; + + data = *(unsigned long *)addr >> (offset * 8); + + regs_set_gpr(regs, reg_data * sizeof(unsigned long), data); + + regs->epc = get_ex_fixup(ex); + return true; +} + bool fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *ex; @@ -65,6 +94,8 @@ bool fixup_exception(struct pt_regs *regs) return ex_handler_bpf(ex, regs); case EX_TYPE_UACCESS_ERR_ZERO: return ex_handler_uaccess_err_zero(ex, regs); + case EX_TYPE_LOAD_UNALIGNED_ZEROPAD: + return ex_handler_load_unaligned_zeropad(ex, regs); } BUG(); From 2febc632c130ced060714e3670f15543326889f9 Mon Sep 17 00:00:00 2001 From: Han Gao Date: Sat, 11 Nov 2023 23:42:00 +0800 Subject: [PATCH 50/52] [NFU] ci: kernel auto build on thead-gcc & mainline-gcc thead-gcc: v2.8.0 mainline-gcc: v13.2 Signed-off-by: Han Gao --- .github/workflows/kernel.yml | 112 +++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 .github/workflows/kernel.yml diff --git a/.github/workflows/kernel.yml b/.github/workflows/kernel.yml new file mode 100644 index 00000000000000..7fb69dd13d5595 --- /dev/null +++ b/.github/workflows/kernel.yml @@ -0,0 +1,112 @@ +name: revyos-mainline-kernel-build + +on: + push: + pull_request: + workflow_dispatch: + schedule: + - cron: "0 2 * * *" + +env: + xuantie_toolchain: https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1698113812618 + toolchain_file_name: Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.8.0-20231018.tar.gz + mainline_toolchain: https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2023.10.18 + mainline_toolchain_file_name: riscv64-glibc-ubuntu-22.04-gcc-nightly-2023.10.18-nightly.tar.gz + wget_alias: 'wget --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 -t 0' + ARCH: riscv + board: lpi4a + KBUILD_BUILD_USER: builder + KBUILD_BUILD_HOST: revyos-riscv-builder + KDEB_COMPRESS: xz + KDEB_CHANGELOG_DIST: unstable + +jobs: + kernel: + strategy: + fail-fast: false + matrix: + include: + - name: thead-gcc + - name: gcc-13 + + runs-on: ubuntu-22.04 + env: + CROSS_COMPILE: riscv64-unknown-linux-gnu- + + steps: + - name: "Update APT sources" + run: | + sudo apt update + + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@main + with: + # this might remove tools that are actually needed, + # if set to "true" but frees about 6 GB + tool-cache: true + # all of these default to true, but feel free to set to + # "false" if necessary for your workflow + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: true + + - name: Install software + run: | + sudo apt install -y gdisk dosfstools g++-12-riscv64-linux-gnu build-essential \ + libncurses-dev gawk flex bison openssl libssl-dev tree \ + dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf device-tree-compiler \ + devscripts debhelper pahole + + - name: Checkout kernel + uses: actions/checkout@v4 + with: + path: 'kernel' + + - name: Compile Kernel && Install + run: | + mkdir -p rootfs/boot + if [[ ${{ matrix.name }} = "thead-gcc" ]]; then + ${wget_alias} ${xuantie_toolchain}/${toolchain_file_name} + tar -xvf ${toolchain_file_name} -C /opt + export PATH="/opt/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.8.0/bin:$PATH" + else + ${wget_alias} ${mainline_toolchain}/${mainline_toolchain_file_name} + tar -xvf ${mainline_toolchain_file_name} -C /opt + export PATH="/opt/riscv/bin:$PATH" + fi + ${CROSS_COMPILE}gcc -v + + pushd kernel + make revyos_defconfig + export KDEB_PKGVERSION="$(date "+%Y.%m.%d.%H.%M")+$(git rev-parse --short HEAD)" + #if [ x"${{ matrix.name }}" = x"gcc-12" ]; then + # echo "CONFIG_THEAD_ISA=n" >> .config + #elif [ x"${{ matrix.name }}" = x"thead-gcc" ]; then + # echo "CONFIG_THEAD_ISA=y" >> .config + #fi + make -j$(nproc) bindeb-pkg LOCALVERSION="-${board}" + make -j$(nproc) dtbs + + # Copy deb + sudo dcmd cp -v ../*.changes ${GITHUB_WORKSPACE}/rootfs/ + + # record commit-id + git rev-parse HEAD > kernel-commitid + sudo cp -v kernel-commitid ${GITHUB_WORKSPACE}/rootfs/boot + + # Install DTB + sudo cp -v arch/riscv/boot/dts/thead/*.dtb ${GITHUB_WORKSPACE}/rootfs/boot/ + popd + + - name: compress + run: tar -zcvf thead-mainline-kernel-${{ matrix.name }}.tar.gz rootfs + + - name: 'Upload Artifact' + uses: actions/upload-artifact@v3 + with: + name: thead-mainline-kernel-${{ matrix.name }}.tar.gz + path: thead-mainline-kernel-${{ matrix.name }}.tar.gz + retention-days: 30 From c0ea2760bc2d74204a3ffcfe0e588375f51d6886 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 24 Dec 2023 20:00:18 -0800 Subject: [PATCH 51/52] riscv: Improve exception and system call latency Many CPUs implement return address branch prediction as a stack. The RISCV architecture refers to this as a return address stack (RAS). If this gets corrupted then the CPU will mispredict at least one but potentally many function returns. There are two issues with the current RISCV exception code: - We are using the alternate link stack (x5/t0) for the indirect branch which makes the hardware think this is a function return. This will corrupt the RAS. - We modify the return address of handle_exception to point to ret_from_exception. This will also corrupt the RAS. Testing the null system call latency before and after the patch: Visionfive2 (StarFive JH7110 / U74) baseline: 189.87 ns patched: 176.76 ns Lichee pi 4a (T-Head TH1520 / C910) baseline: 666.58 ns patched: 636.90 ns Just over 7% on the U74 and just over 4% on the C910. Signed-off-by: Anton Blanchard Reviewed-by: Jisheng Zhang --- arch/riscv/kernel/entry.S | 21 ++++++++++++++------- arch/riscv/kernel/stacktrace.c | 14 +++++++++++++- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 278d01d2911fd5..2a82ba112add1d 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -82,7 +82,6 @@ _save_context: la gp, __global_pointer$ .option pop move a0, sp /* pt_regs */ - la ra, ret_from_exception /* * MSB of cause differentiates between @@ -91,7 +90,10 @@ _save_context: bge s4, zero, 1f /* Handle interrupts */ - tail do_irq + call do_irq +.globl ret_from_irq_exception +ret_from_irq_exception: + j ret_from_exception 1: /* Handle other exceptions */ slli t0, s4, RISCV_LGPTR @@ -99,11 +101,16 @@ _save_context: la t2, excp_vect_table_end add t0, t1, t0 /* Check if exception code lies within bounds */ - bgeu t0, t2, 1f - REG_L t0, 0(t0) - jr t0 -1: - tail do_trap_unknown + bgeu t0, t2, 3f + REG_L t1, 0(t0) +2: jalr ra,t1 +.globl ret_from_other_exception +ret_from_other_exception: + j ret_from_exception +3: + + la t1, do_trap_unknown + j 2b SYM_CODE_END(handle_exception) /* diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 64a9c093aef93a..b9cd131bbc4c08 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -17,6 +17,18 @@ #ifdef CONFIG_FRAME_POINTER extern asmlinkage void ret_from_exception(void); +extern asmlinkage void ret_from_irq_exception(void); +extern asmlinkage void ret_from_other_exception(void); + +static inline bool is_exception_frame(unsigned long pc) +{ + if ((pc == (unsigned long)ret_from_exception) || + (pc == (unsigned long)ret_from_irq_exception) || + (pc == (unsigned long)ret_from_other_exception)) + return true; + + return false; +} void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *arg) @@ -62,7 +74,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, fp = frame->fp; pc = ftrace_graph_ret_addr(current, NULL, frame->ra, &frame->ra); - if (pc == (unsigned long)ret_from_exception) { + if (is_exception_frame(pc)) { if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc))) break; From ed03c626e1f547b1ceef88ec92adfa0c60edafd4 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Sat, 30 Dec 2023 00:33:47 +0200 Subject: [PATCH 52/52] cpufreq: correct typo in config name --- arch/riscv/configs/revyos_defconfig | 2 +- drivers/cpufreq/Kconfig | 2 +- drivers/cpufreq/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/riscv/configs/revyos_defconfig b/arch/riscv/configs/revyos_defconfig index 87b4fa6e137468..bd906a780d3950 100644 --- a/arch/riscv/configs/revyos_defconfig +++ b/arch/riscv/configs/revyos_defconfig @@ -58,7 +58,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPUFREQ_DT=m CONFIG_CPUFREQ_DT_PLATDEV=y -CONFIG_RISV_THEAD_LIGHT_CPUFREQ=y +CONFIG_RISCV_THEAD_LIGHT_CPUFREQ=y CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y # CONFIG_COMPAT_32BIT_TIME is not set diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 0c61e7d7f8c721..dae879268f1b00 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -312,7 +312,7 @@ config QORIQ_CPUFREQ This adds the CPUFreq driver support for Freescale QorIQ SoCs which are capable of changing the CPU's frequency dynamically. -config RISV_THEAD_LIGHT_CPUFREQ +config RISCV_THEAD_LIGHT_CPUFREQ tristate "CPU frequency scaling driver for Thead light SoCs" depends on OF && COMMON_CLK select CLK_LIGHT diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 379fac60bb1655..195cb8ff1ead6d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -107,4 +107,4 @@ obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o -obj-$(CONFIG_RISV_THEAD_LIGHT_CPUFREQ) += light-mpw-cpufreq.o +obj-$(CONFIG_RISCV_THEAD_LIGHT_CPUFREQ) += light-mpw-cpufreq.o