From 80cbe0d214559f279d46fa01039461523811f2c6 Mon Sep 17 00:00:00 2001 From: wangjianxin Date: Thu, 18 Jul 2024 12:16:46 +0800 Subject: [PATCH] add k230 reboot reset Signed-off-by: wangjianxin --- .../boot/dts/canaan/k230-canmv-01studio.dts | 2 + arch/riscv/boot/dts/canaan/k230.dtsi | 15 +- drivers/mmc/host/sdhci-of-kendryte.c | 282 ++++++------ drivers/reset/Kconfig | 11 + drivers/reset/Makefile | 1 + drivers/reset/reset-k230.c | 401 ++++++++++++++++++ 6 files changed, 570 insertions(+), 142 deletions(-) create mode 100644 drivers/reset/reset-k230.c diff --git a/arch/riscv/boot/dts/canaan/k230-canmv-01studio.dts b/arch/riscv/boot/dts/canaan/k230-canmv-01studio.dts index 89e93784e8f91..813cdbaf524b9 100644 --- a/arch/riscv/boot/dts/canaan/k230-canmv-01studio.dts +++ b/arch/riscv/boot/dts/canaan/k230-canmv-01studio.dts @@ -28,6 +28,8 @@ cap-sd-highspeed; rx_delay_line = <0x0d>; tx_delay_line = <0xb0>; + clocks = <&sd0_cclk_gate>,<&sd0_cclk_gate>; + clock-names = "core", "bus"; }; &mmc_sd1{ status = "okay"; diff --git a/arch/riscv/boot/dts/canaan/k230.dtsi b/arch/riscv/boot/dts/canaan/k230.dtsi index 3d66be43dca06..b88830efd9067 100644 --- a/arch/riscv/boot/dts/canaan/k230.dtsi +++ b/arch/riscv/boot/dts/canaan/k230.dtsi @@ -213,9 +213,22 @@ g-tx-fifo-size = <512 1024 64 64 64 64>; status = "disabled"; }; + mmc_sd0: sdhci0@91580000 { + compatible = "canaan,k230-dw-mshc"; + reg = <0x0 0x91580000 0x0 0x1000>; + interrupts = <142 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "sdhci0irq"; + clocks = <&dummy_sd>,<&dummy_sd>; + clock-names = "core", "bus"; + max-frequency = <200000000>; + bus-width = <8>; + sdhci,auto-cmd12; + dma-noncoherent; + status = "disabled"; + }; mmc_sd1: sdhci1@91581000 { - compatible = "kendryte,k230-dw-mshc"; + compatible = "canaan,k230-dw-mshc"; reg = <0x0 0x91581000 0x0 0x1000>; interrupts = <144 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "sdhci1irq"; diff --git a/drivers/mmc/host/sdhci-of-kendryte.c b/drivers/mmc/host/sdhci-of-kendryte.c index 0955bbb2079fd..ba8fd024f2bc5 100644 --- a/drivers/mmc/host/sdhci-of-kendryte.c +++ b/drivers/mmc/host/sdhci-of-kendryte.c @@ -23,7 +23,6 @@ #define EMMC_CTRL_R (DWC_MSHC_PTR_VENDOR1 + 0x2c) //16bit #define CARD_IS_EMMC 0x0 //1bit - #define DWC_MSHC_PTR_PHY_REGS 0x300 #define DWC_MSHC_PHY_CNFG (DWC_MSHC_PTR_PHY_REGS + 0x0) #define PAD_SN_LSB 20 @@ -55,97 +54,99 @@ #define DWC_MSHC_SMPLDL_CNFG (DWC_MSHC_PTR_PHY_REGS + 0x20) #define DWC_MSHC_ATDL_CNFG (DWC_MSHC_PTR_PHY_REGS + 0x21) -#define DWC_MSHC_PHY_PAD_SD_CLK \ - ((1 << TXSLEW_N_LSB) | (3 << TXSLEW_P_LSB) | (0 << WEAKPULL_EN_LSB) | \ +#define DWC_MSHC_PHY_PAD_SD_CLK \ + ((1 << TXSLEW_N_LSB) | (3 << TXSLEW_P_LSB) | (0 << WEAKPULL_EN_LSB) | \ (2 << RXSEL_LSB)) -#define DWC_MSHC_PHY_PAD_SD_DAT \ - ((1 << TXSLEW_N_LSB) | (3 << TXSLEW_P_LSB) | (1 << WEAKPULL_EN_LSB) | \ +#define DWC_MSHC_PHY_PAD_SD_DAT \ + ((1 << TXSLEW_N_LSB) | (3 << TXSLEW_P_LSB) | (1 << WEAKPULL_EN_LSB) | \ (2 << RXSEL_LSB)) -#define DWC_MSHC_PHY_PAD_SD_STB \ - ((1 << TXSLEW_N_LSB) | (3 << TXSLEW_P_LSB) | (2 << WEAKPULL_EN_LSB) | \ +#define DWC_MSHC_PHY_PAD_SD_STB \ + ((1 << TXSLEW_N_LSB) | (3 << TXSLEW_P_LSB) | (2 << WEAKPULL_EN_LSB) | \ (2 << RXSEL_LSB)) -#define DWC_MSHC_PHY_PAD_EMMC_CLK \ - ((2 << TXSLEW_N_LSB) | (2 << TXSLEW_P_LSB) | (0 << WEAKPULL_EN_LSB) | \ +#define DWC_MSHC_PHY_PAD_EMMC_CLK \ + ((2 << TXSLEW_N_LSB) | (2 << TXSLEW_P_LSB) | (0 << WEAKPULL_EN_LSB) | \ (1 << RXSEL_LSB)) - // (0 << RXSEL_LSB)) +// (0 << RXSEL_LSB)) -#define DWC_MSHC_PHY_PAD_EMMC_DAT \ - ((2 << TXSLEW_N_LSB) | (2 << TXSLEW_P_LSB) | (1 << WEAKPULL_EN_LSB) | \ +#define DWC_MSHC_PHY_PAD_EMMC_DAT \ + ((2 << TXSLEW_N_LSB) | (2 << TXSLEW_P_LSB) | (1 << WEAKPULL_EN_LSB) | \ (1 << RXSEL_LSB)) -#define DWC_MSHC_PHY_PAD_EMMC_STB \ - ((2 << TXSLEW_N_LSB) | (2 << TXSLEW_P_LSB) | (2 << WEAKPULL_EN_LSB) | \ +#define DWC_MSHC_PHY_PAD_EMMC_STB \ + ((2 << TXSLEW_N_LSB) | (2 << TXSLEW_P_LSB) | (2 << WEAKPULL_EN_LSB) | \ (1 << RXSEL_LSB)) /* DWCMSHC specific Mode Select value */ -#define DWCMSHC_CTRL_HS400 0x7 +#define DWCMSHC_CTRL_HS400 0x7 #define BOUNDARY_OK(addr, len) \ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) struct dwcmshc_priv { - struct clk *bus_clk; + struct clk *bus_clk; bool is_emmc_card; - u32 tx_delay_line; - u32 rx_delay_line; - u8 mshc_ctrl_r; - bool io_fixed_1v8; - void __iomem *hs_regs; - bool have_phy; + u32 tx_delay_line; + u32 rx_delay_line; + u8 mshc_ctrl_r; + bool io_fixed_1v8; + void __iomem *hs_regs; + bool have_phy; }; static void dwcmshc_phy_1_8v_init(struct sdhci_host *host) { - sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_DAT, DWC_MSHC_CMDPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_DAT, DWC_MSHC_DATPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_CLK, DWC_MSHC_CLKPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_STB, DWC_MSHC_STBPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_DAT, DWC_MSHC_RSTNPAD_CNFG); - + sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_DAT, DWC_MSHC_CMDPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_DAT, DWC_MSHC_DATPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_CLK, DWC_MSHC_CLKPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_STB, DWC_MSHC_STBPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_EMMC_DAT, DWC_MSHC_RSTNPAD_CNFG); } static void dwcmshc_phy_3_3v_init(struct sdhci_host *host) { - sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_DAT, DWC_MSHC_CMDPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_DAT, DWC_MSHC_DATPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_CLK, DWC_MSHC_CLKPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_STB, DWC_MSHC_STBPAD_CNFG); - sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_DAT, DWC_MSHC_RSTNPAD_CNFG); - + sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_DAT, DWC_MSHC_CMDPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_DAT, DWC_MSHC_DATPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_CLK, DWC_MSHC_CLKPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_STB, DWC_MSHC_STBPAD_CNFG); + sdhci_writew(host, DWC_MSHC_PHY_PAD_SD_DAT, DWC_MSHC_RSTNPAD_CNFG); } static void dwcmshc_phy_delay_config(struct sdhci_host *host) { - struct sdhci_pltfm_host *pltfm_host; + struct sdhci_pltfm_host *pltfm_host; struct dwcmshc_priv *priv; - pltfm_host = sdhci_priv(host); + + pltfm_host = sdhci_priv(host); priv = sdhci_pltfm_priv(pltfm_host); sdhci_writeb(host, 1, DWC_MSHC_COMMDL_CNFG); - if (priv->tx_delay_line > 256) { - pr_info("%s: tx_delay_line err\n", mmc_hostname(host->mmc)); - } else if (priv->tx_delay_line > 128) { - sdhci_writeb(host, 0x1, DWC_MSHC_SDCLKDL_CNFG); - sdhci_writeb(host, priv->tx_delay_line - 128, DWC_MSHC_SDCLKDL_DC); - } else { - sdhci_writeb(host, 0x0, DWC_MSHC_SDCLKDL_CNFG); - sdhci_writeb(host, priv->tx_delay_line, DWC_MSHC_SDCLKDL_DC); - } - + if (priv->tx_delay_line > 256) { + pr_info("%s: tx_delay_line err\n", mmc_hostname(host->mmc)); + } else if (priv->tx_delay_line > 128) { + sdhci_writeb(host, 0x1, DWC_MSHC_SDCLKDL_CNFG); + sdhci_writeb(host, priv->tx_delay_line - 128, + DWC_MSHC_SDCLKDL_DC); + } else { + sdhci_writeb(host, 0x0, DWC_MSHC_SDCLKDL_CNFG); + sdhci_writeb(host, priv->tx_delay_line, DWC_MSHC_SDCLKDL_DC); + } + sdhci_writeb(host, priv->rx_delay_line, DWC_MSHC_SMPLDL_CNFG); sdhci_writeb(host, 0xc, DWC_MSHC_ATDL_CNFG); - sdhci_writel(host, (sdhci_readl(host, SDHCI_VENDER_AT_CTRL_REG) | \ - BIT(16) | BIT(17) | BIT(19) | BIT(20)), SDHCI_VENDER_AT_CTRL_REG); - sdhci_writel(host,0x0,SDHCI_VENDER_AT_STAT_REG); - return; + sdhci_writel(host, + (sdhci_readl(host, SDHCI_VENDER_AT_CTRL_REG) | BIT(16) | + BIT(17) | BIT(19) | BIT(20)), + SDHCI_VENDER_AT_CTRL_REG); + sdhci_writel(host, 0x0, SDHCI_VENDER_AT_STAT_REG); } static int dwcmshc_phy_init(struct sdhci_host *host) { u32 reg; unsigned int timeout = 15000; - struct sdhci_pltfm_host *pltfm_host; + struct sdhci_pltfm_host *pltfm_host; struct dwcmshc_priv *priv; - pltfm_host = sdhci_priv(host); + + pltfm_host = sdhci_priv(host); priv = sdhci_pltfm_priv(pltfm_host); /* reset phy */ sdhci_writew(host, 0, DWC_MSHC_PHY_CNFG); @@ -153,14 +154,15 @@ static int dwcmshc_phy_init(struct sdhci_host *host) /* Disable the clock */ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - if (priv->io_fixed_1v8) { - u32 data = sdhci_readw(host, SDHCI_HOST_CONTROL2); - data |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, data, SDHCI_HOST_CONTROL2); - dwcmshc_phy_1_8v_init(host); - } else { - dwcmshc_phy_3_3v_init(host); - } + if (priv->io_fixed_1v8) { + u32 data = sdhci_readw(host, SDHCI_HOST_CONTROL2); + + data |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, data, SDHCI_HOST_CONTROL2); + dwcmshc_phy_1_8v_init(host); + } else { + dwcmshc_phy_3_3v_init(host); + } dwcmshc_phy_delay_config(host); @@ -169,9 +171,9 @@ static int dwcmshc_phy_init(struct sdhci_host *host) reg = sdhci_readl(host, DWC_MSHC_PHY_CNFG); if (reg & PHY_PWRGOOD) break; - if (!timeout) { + if (!timeout) return -1; - } + timeout--; usleep_range(10, 15); @@ -198,21 +200,20 @@ static void dwcmshc_sdhci_reset(struct sdhci_host *host, u8 mask) /*host reset*/ sdhci_reset(host, mask); - if(mask == SDHCI_RESET_ALL) { - emmc_ctl = sdhci_readw(host, EMMC_CTRL_R); - - if (priv->is_emmc_card) { - emmc_ctl |= (1 << CARD_IS_EMMC); - } else { - emmc_ctl &=~(1 << CARD_IS_EMMC); - } - sdhci_writeb(host, emmc_ctl, EMMC_CTRL_R); - if(priv->have_phy) { - dwcmshc_phy_init(host); - } else { - sdhci_writeb(host, priv->mshc_ctrl_r, MSHC_CTRL_R); - } - } + if (mask == SDHCI_RESET_ALL) { + emmc_ctl = sdhci_readw(host, EMMC_CTRL_R); + + if (priv->is_emmc_card) + emmc_ctl |= (1 << CARD_IS_EMMC); + else + emmc_ctl &= ~(1 << CARD_IS_EMMC); + + sdhci_writeb(host, emmc_ctl, EMMC_CTRL_R); + if (priv->have_phy) + dwcmshc_phy_init(host); + else + sdhci_writeb(host, priv->mshc_ctrl_r, MSHC_CTRL_R); + } } /* @@ -238,7 +239,8 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, sdhci_adma_write_desc(host, desc, addr, len, cmd); } -static void dwcmshc_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) +static void dwcmshc_sdhci_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) { u16 ctrl_2; @@ -246,10 +248,9 @@ static void dwcmshc_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned ti /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; if ((timing == MMC_TIMING_MMC_HS200) || - (timing == MMC_TIMING_UHS_SDR104)) { + (timing == MMC_TIMING_UHS_SDR104)) { ctrl_2 |= SDHCI_CTRL_UHS_SDR104; - } - else if (timing == MMC_TIMING_UHS_SDR12) + } else if (timing == MMC_TIMING_UHS_SDR12) ctrl_2 |= SDHCI_CTRL_UHS_SDR12; else if ((timing == MMC_TIMING_UHS_SDR25) || (timing == MMC_TIMING_MMC_HS)) @@ -257,7 +258,7 @@ static void dwcmshc_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned ti else if (timing == MMC_TIMING_UHS_SDR50) ctrl_2 |= SDHCI_CTRL_UHS_SDR50; else if ((timing == MMC_TIMING_UHS_DDR50) || - (timing == MMC_TIMING_MMC_DDR52)) + (timing == MMC_TIMING_MMC_DDR52)) ctrl_2 |= SDHCI_CTRL_UHS_DDR50; else if (timing == MMC_TIMING_MMC_HS400) { ctrl_2 |= DWCMSHC_CTRL_HS400; /* Non-standard */ @@ -283,13 +284,13 @@ static void k230_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) } static const struct sdhci_ops sdhci_dwcmshc_kendryte_ops = { - .set_clock = k230_sdhci_set_clock, - .set_bus_width = sdhci_set_bus_width, - .set_uhs_signaling = dwcmshc_sdhci_set_uhs_signaling, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, - .reset = dwcmshc_sdhci_reset, - .adma_write_desc = dwcmshc_adma_write_desc, - .voltage_switch = dwcmshc_phy_1_8v_init, + .set_clock = k230_sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_sdhci_set_uhs_signaling, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .reset = dwcmshc_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + .voltage_switch = dwcmshc_phy_1_8v_init, }; static const struct sdhci_pltfm_data sdhci_dwcmshc_kendryte_pdata = { @@ -297,18 +298,16 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_kendryte_pdata = { .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, }; -/* This api is for wifi driver rescan the sdio device, - * ugly but it is needed */ -static unsigned int slot_index = 0; -static struct mmc_host *__mmc__host[3] = {NULL}; +static unsigned int slot_index; +static struct mmc_host *__mmc__host[3] = { NULL }; int plat_sdio_rescan(int slot) { struct mmc_host *mmc = __mmc__host[slot]; if (mmc == NULL) { - pr_err("invalid mmc, please check the argument\n"); - return -EINVAL; + pr_err("invalid mmc, please check the argument\n"); + return -EINVAL; } mmc_detect_change(mmc, 0); @@ -341,51 +340,52 @@ static int dwcmshc_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); priv = sdhci_pltfm_priv(pltfm_host); - priv->hs_regs = ioremap(hi_sys_config_addr,0x400); - - if(memcmp(host->hw_name,"91581000",8) == 0) { - priv->have_phy = 0; - data = readl(priv->hs_regs + 8); - data |= 1<<2 | 1<<0; - writel(data, priv->hs_regs + 8); - } else { - priv->have_phy = 1; - data = readl(priv->hs_regs + 0); - data |= 1<<6 | 1<<4; - writel(data, priv->hs_regs + 0); - } - - if (device_property_present(&pdev->dev, "is_emmc")) { - priv->is_emmc_card = 1; - } else { - priv->is_emmc_card = 0; - } - - if(priv->have_phy) { - if (device_property_present(&pdev->dev, "io_fixed_1v8")) { - priv->io_fixed_1v8 = 1; - } else { - priv->io_fixed_1v8 = 0; - } - err = device_property_read_u32(&pdev->dev, "tx_delay_line", &priv->tx_delay_line); - if(err) - priv->tx_delay_line = 0; - - err = device_property_read_u32(&pdev->dev, "rx_delay_line", &priv->rx_delay_line); - if(err) - priv->rx_delay_line = 0; - - } else { - /*sdio:(fpga board) Launches CMD/DATA with respect to positive edge of cclk_tx */ - err = device_property_read_u8(&pdev->dev, "mshc_ctrl_r", &priv->mshc_ctrl_r); - if(err) - priv->mshc_ctrl_r = 0; - } - - if (priv->io_fixed_1v8) { - host->flags &= ~SDHCI_SIGNALING_330; + priv->hs_regs = ioremap(hi_sys_config_addr, 0x400); + + if (memcmp(host->hw_name, "91581000", 8) == 0) { + priv->have_phy = 0; + data = readl(priv->hs_regs + 8); + data |= 1 << 2 | 1 << 0; + writel(data, priv->hs_regs + 8); + } else { + priv->have_phy = 1; + data = readl(priv->hs_regs + 0); + data |= 1 << 6 | 1 << 4; + writel(data, priv->hs_regs + 0); + } + + if (device_property_present(&pdev->dev, "is_emmc")) + priv->is_emmc_card = 1; + else + priv->is_emmc_card = 0; + + if (priv->have_phy) { + if (device_property_present(&pdev->dev, "io_fixed_1v8")) + priv->io_fixed_1v8 = 1; + else + priv->io_fixed_1v8 = 0; + + err = device_property_read_u32(&pdev->dev, "tx_delay_line", + &priv->tx_delay_line); + if (err) + priv->tx_delay_line = 0x40; + + err = device_property_read_u32(&pdev->dev, "rx_delay_line", + &priv->rx_delay_line); + if (err) + priv->rx_delay_line = 0xd; + + } else { + /*sdio:(fpga board) Launches CMD/DATA with respect to positive edge of cclk_tx */ + err = device_property_read_u8(&pdev->dev, "mshc_ctrl_r", + &priv->mshc_ctrl_r); + if (err) + priv->mshc_ctrl_r = 0; } + if (priv->io_fixed_1v8) + host->flags &= ~SDHCI_SIGNALING_330; + pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(pltfm_host->clk)) { err = PTR_ERR(pltfm_host->clk); @@ -400,7 +400,7 @@ static int dwcmshc_probe(struct platform_device *pdev) if (!IS_ERR(priv->bus_clk)) clk_prepare_enable(priv->bus_clk); - /* new fix: storage mmc host to array */ + /* new fix: storage mmc host to array */ __mmc__host[slot_index++] = host->mmc; err = mmc_of_parse(host->mmc); @@ -434,7 +434,7 @@ static int dwcmshc_remove(struct platform_device *pdev) clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(priv->bus_clk); - iounmap(priv->hs_regs); + iounmap(priv->hs_regs); sdhci_pltfm_free(pdev); @@ -484,7 +484,7 @@ static int dwcmshc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume); static const struct of_device_id sdhci_dwcmshc_kendryte_dt_ids[] = { - { .compatible = "kendryte,k230-dw-mshc" }, + { .compatible = "canaan,k230-dw-mshc" }, {} }; MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_kendryte_dt_ids); diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 9273d1e6fe80b..7461ffbe40be8 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -102,6 +102,17 @@ config RESET_K210 Say Y if you want to control reset signals provided by this controller. +config RESET_K230 + bool "Reset controller driver for Canaan Kendryte K230 SoC" + depends on RISCV && OF && ARCH_CANAAN + select MFD_SYSCON + default ARCH_CANAAN + help + Support for the Canaan Kendryte K230 RISC-V SoC reset controller. + Say Y if you want to control reset signals + provided by this + controller. + config RESET_LANTIQ bool "Lantiq XWAY Reset Driver" if COMPILE_TEST default SOC_TYPE_XWAY diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 5c858e62241a9..e00ff19d4c42c 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o obj-$(CONFIG_RESET_K210) += reset-k210.o +obj-$(CONFIG_RESET_K230) += reset-k230.o obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o diff --git a/drivers/reset/reset-k230.c b/drivers/reset/reset-k230.c new file mode 100644 index 0000000000000..013c4834f4baa --- /dev/null +++ b/drivers/reset/reset-k230.c @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: GPL-2.0-only +/**************************************************** + * 1. 写provider.dtsi,组织reset模块的形式(标准格式:phandle+specifier), + * 使得扫描device tree后生成的id格式统一 + * 2. 在dt-bindings目录下写头文件,将所有的模块按照一定的格式描述出来 + * 3. 编写驱动文件,按照不同的类型reset对应的模块。 + * + * id的格式:根据reset_consumer.dtsi中定义的格式类型,即 + * _________________ + * | phandle | offset | type | done | assert | + * ————————————————— + * 经过xlate函数翻译之后,将reset属性翻译成id,其中id的形式如下: + * 31 16|15 14|13 7|6 0 + * —————————————————— + * | offset | type | done | reset | + * ———————————————————— + * id最终将提供给reset_control_ops使用 + */ + +/* + * Copyright (c) 2016-2017 Linaro Ltd. + * Copyright (c) 2022, Canaan Bright Sight Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define K230_RESET_DEBUG + +struct k230_reset_controller { + spinlock_t lock; + void __iomem *membase; + struct reset_controller_dev rst; +}; + +#define to_k230_reset_controller(_rst) \ + container_of(_rst, struct k230_reset_controller, rst) + +static int k230_reset_of_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + u32 offset; + u32 type; + u32 done; + u32 reset; + + offset = (reset_spec->args[0] << K230_RESET_REG_OFFSET_SHIFT) & + K230_RESET_REG_OFFSET_MASK; + type = (reset_spec->args[1] << K230_RESET_TYPE_SHIFT) & + K230_RESET_TYPE_MASK; + done = (reset_spec->args[2] << K230_RESET_DONE_BIT_SHIFT) & + K230_RESET_DONE_BIT_MASK; + reset = (reset_spec->args[3] << K230_RESET_ASSERT_BIT_SHIFT) & + K230_RESET_ASSERT_BIT_MASK; + + return (offset | type | done | reset); +} + +static int k230_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct k230_reset_controller *rstc = to_k230_reset_controller(rcdev); + unsigned long flags; + u32 offset = (id & K230_RESET_REG_OFFSET_MASK) >> + K230_RESET_REG_OFFSET_SHIFT; + u32 type = (id & K230_RESET_TYPE_MASK) >> K230_RESET_TYPE_SHIFT; + u32 done = (id & K230_RESET_DONE_BIT_MASK) >> K230_RESET_DONE_BIT_SHIFT; + u32 reset = (id & K230_RESET_ASSERT_BIT_MASK) >> + K230_RESET_ASSERT_BIT_SHIFT; + u32 reg; + + spin_lock_irqsave(&rstc->lock, flags); + switch (type) { + case K230_RESET_TYPE_CPU: { + /* clear done bit */ + reg = readl(rstc->membase + offset); + reg |= (1 << done); + reg |= (1 << (done + 0x10)); // note: write enable + writel(reg, rstc->membase + offset); + + /* set reset bit */ + reg |= (1 << reset); + reg |= (1 << (reset + 0x10)); // note: write enable + writel(reg, rstc->membase + offset); + + udelay(10); + + /* clear reset bit */ + if (offset == 0xc) { + reg &= ~(1 << reset); + reg &= (1 << (reset + 0x10)); // note: write enable + writel(reg, rstc->membase + offset); + } + + /* wait done bit set */ + while (1) { + reg = readl(rstc->membase + offset); + if (reg & (1 << done)) { + /* clear done and break */ + writel(reg, rstc->membase + offset); + break; + } + } + break; + } + case K230_RESET_TYPE_HW_AUTO_DONE: { + /* clear done bit */ + reg = readl(rstc->membase + offset); + reg |= (1 << done); + writel(reg, rstc->membase + offset); + + /* set reset bit */ + reg = readl(rstc->membase + offset); + + reg |= (1 << reset); + writel(reg, rstc->membase + offset); + + /* wait done bit set */ + while (1) { + reg = readl(rstc->membase + offset); + if (reg & (1 << done)) { + /* clear done and break */ + writel(reg, rstc->membase + offset); + break; + } + } + break; + } + case K230_RESET_TYPE_SW_SET_DONE: { + /* set reset bit */ + reg = readl(rstc->membase + offset); + if ((offset == 0x20) || (offset == 0x24) || (offset == 0x80) || + (offset == 0x64)) { + reg |= (0 << reset); //special,复位:reset=0 + } else if ((offset == 0x4) || (offset == 0xc)) { + reg |= (1 << reset); + reg |= (1 << (reset + 0x10)); //note: write enable + } else { + reg |= (1 << reset); + } + writel(reg, rstc->membase + offset); + + udelay(10); + + /* clear reset bit */ + if ((offset != 0x4) && + (offset != 0xc)) { //special,0x4, 0xc寄存器是自动清零 + if (offset == 0xa8) { + reg &= ~(1 << reset); + writel(reg, rstc->membase + offset); + } else { + reg &= ~(0 << reset); + writel(reg, rstc->membase + offset); + } + } + + break; + } + default: { + break; + } + } + + spin_unlock_irqrestore(&rstc->lock, flags); + return 0; +} + +static int k230_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct k230_reset_controller *rstc = to_k230_reset_controller(rcdev); + unsigned long flags; + u32 offset = (id & K230_RESET_REG_OFFSET_MASK) >> + K230_RESET_REG_OFFSET_SHIFT; + u32 type = (id & K230_RESET_TYPE_MASK) >> K230_RESET_TYPE_SHIFT; + /*u32 done = (id & K230_RESET_DONE_BIT_MASK) >> K230_RESET_DONE_BIT_SHIFT;*/ + u32 reset = (id & K230_RESET_ASSERT_BIT_MASK) >> + K230_RESET_ASSERT_BIT_SHIFT; + u32 reg; + + // if(type == K230_RESET_TYPE_HW_AUTO_DONE) { + // pr_err("hardware auto done reset DOESNOT support reset assert!"); + // } else { + // spin_lock_irqsave(&rstc->lock, flags); + // reg = readl(rstc->membase+offset); + // /* set reset bit */ + // reg |= (1 << reset); + // writel(reg, rstc->membase+offset); + // spin_unlock_irqrestore(&rstc->lock, flags); + // } + if (type == K230_RESET_TYPE_HW_AUTO_DONE) { + pr_err("hardware auto done reset DOESNOT support reset assert!"); + } else if (type == K230_RESET_TYPE_CPU) { + spin_lock_irqsave(&rstc->lock, flags); + reg = readl(rstc->membase + offset); + /* set reset bit */ + reg |= (1 << reset); + reg |= (1 << (reset + 0x10)); // note: write enable + writel(reg, rstc->membase + offset); + spin_unlock_irqrestore(&rstc->lock, flags); + } else { + spin_lock_irqsave(&rstc->lock, flags); + reg = readl(rstc->membase + offset); + /* set reset bit */ + if ((offset == 0x20) || (offset == 0x24) || (offset == 0x80) || + (offset == 0x64)) { + reg |= (0 << reset); //special,复位:reset=0 + } else if ((offset == 0x4) || (offset == 0xc)) { + reg |= (1 << reset); + reg |= (1 << (reset + 0x10)); //note: write enable + } else { + reg |= (1 << reset); + } + writel(reg, rstc->membase + offset); + spin_unlock_irqrestore(&rstc->lock, flags); + } + return 0; +} + +static int k230_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct k230_reset_controller *rstc = to_k230_reset_controller(rcdev); + unsigned long flags; + u32 offset = (id & K230_RESET_REG_OFFSET_MASK) >> + K230_RESET_REG_OFFSET_SHIFT; + u32 type = (id & K230_RESET_TYPE_MASK) >> K230_RESET_TYPE_SHIFT; + u32 done = (id & K230_RESET_DONE_BIT_MASK) >> K230_RESET_DONE_BIT_SHIFT; + u32 reset = (id & K230_RESET_ASSERT_BIT_MASK) >> + K230_RESET_ASSERT_BIT_SHIFT; + u32 reg; + + // if(type == K230_RESET_TYPE_HW_AUTO_DONE) { + // pr_err("hardware auto done reset DOESNOT support reset assert!"); + // } else { + // spin_lock_irqsave(&rstc->lock, flags); + // reg = readl(rstc->membase+offset); + // /* clear reset bit */ + // reg &= ~(1 << reset); + // writel(reg, rstc->membase+offset); + // if(type == K230_RESET_TYPE_CPU) { + // /* check bit done */ + // while(1) { + // reg = readl(rstc->membase+offset); + // if(reg & (1 << done)) { + // /* clear done and break */ + // writel(reg, rstc->membase+offset); + // break; + // } + // } + // } + // spin_unlock_irqrestore(&rstc->lock, flags); + if (type == K230_RESET_TYPE_HW_AUTO_DONE) { + pr_err("hardware auto done reset DOESNOT support reset assert!"); + } else if (type == K230_RESET_TYPE_CPU) { + spin_lock_irqsave(&rstc->lock, flags); + reg = readl(rstc->membase + offset); + /* clear reset bit */ + if (offset == 0xc) { + reg &= ~(1 << reset); + reg &= (1 << (reset + 0x10)); // note: write enable + writel(reg, rstc->membase + offset); + } + + /* wait done bit set */ + while (1) { + reg = readl(rstc->membase + offset); + if (reg & (1 << done)) { + /* clear done and break */ + writel(reg, rstc->membase + offset); + break; + } + } + spin_unlock_irqrestore(&rstc->lock, flags); + } else { + spin_lock_irqsave(&rstc->lock, flags); + reg = readl(rstc->membase + offset); + /* clear reset bit */ + if ((offset != 0x4) && + (offset != 0xc)) { //special,0x4, 0xc寄存器是自动清零 + if (offset == 0xa8) { + reg &= ~(1 << reset); + writel(reg, rstc->membase + offset); + } else { + reg &= ~(0 << reset); + writel(reg, rstc->membase + offset); + } + } + spin_unlock_irqrestore(&rstc->lock, flags); + } + return 0; +} + +static const struct reset_control_ops k230_reset_ops = { + .reset = k230_reset, + .assert = k230_reset_assert, + .deassert = k230_reset_deassert, +}; +static int k230_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ +#define SYSCTL_BOOT_BASE_ADDR 0x91102000U +#define CPU0_RST_CTL 0x60 + + void __iomem *MMAP_ADDR = + ioremap(SYSCTL_BOOT_BASE_ADDR + CPU0_RST_CTL, 4); + + writel(((1 << 0) | (1 << 16)), MMAP_ADDR); + + while (1) + ; + + return 0; +} + +static int k230_restart_register(void) +{ + static struct notifier_block restart_handler; + + restart_handler.notifier_call = k230_restart; + restart_handler.priority = 128; + + return register_restart_handler(&restart_handler); +} + +static int k230_reset_probe(struct platform_device *pdev) +{ + struct k230_reset_controller *rstc; + struct resource *res; + + k230_restart_register(); + + rstc = devm_kmalloc(&pdev->dev, sizeof(*rstc), GFP_KERNEL); + if (!rstc) + return -1; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rstc->membase = + devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!rstc->membase) { + pr_err("k230_reset_init devm_ioremap error!"); + return -1; + } +#ifdef K230_RESET_DEBUG + pr_info("[K230_RESET]:sysctl reset phy addr 0x%08x", (int)res->start); +#endif + + spin_lock_init(&rstc->lock); + rstc->rst.owner = THIS_MODULE; + rstc->rst.ops = &k230_reset_ops; + rstc->rst.of_node = pdev->dev.of_node; + rstc->rst.of_reset_n_cells = 4; + rstc->rst.of_xlate = k230_reset_of_xlate; + if (reset_controller_register(&rstc->rst) == 0) { +#ifdef K230_RESET_DEBUG + pr_info("[K230_RESET]: ok!"); +#endif + } else { + pr_info("[K230_RESET]: error!"); + } + + return 0; +} + +void k230_reset_exit(struct k230_reset_controller *rstc) +{ + reset_controller_unregister(&rstc->rst); +} + +static const struct of_device_id k230_reset_match[] = { + { + .compatible = "canaan,k230-sysctl-reset", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, k230_reset_match); + +static struct platform_driver + k230_reset_driver = { .probe = k230_reset_probe, + .driver = { + .name = "k230-sysctl-reset", + .of_match_table = k230_reset_match, + } }; + +builtin_platform_driver(k230_reset_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:k230-sysctl-reset"); +MODULE_DESCRIPTION("Canaan K230 Reset Driver");