summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-06-29 13:44:52 -0600
committerTom Rini <[email protected]>2026-06-29 15:29:56 -0600
commit0d8e33717d7e5b2a4034cc88f18bf233f77801e7 (patch)
tree2ec6524c4386254d6abff755ce88759f5a01975c /drivers
parentd5046398433e48e7b0b664c1ee3e4e2af6f861a8 (diff)
parent4a72fd9fb09109857303ca64fd259009e1d4b554 (diff)
Merge patch series "arm: aspeed: add initial AST2700 SoC support"
Ryan Chen <[email protected]> says: AST2700 is the 8th generation of Integrated Remote Management Processor introduced by ASPEED Technology Inc. It is a Board Management Controller (BMC) SoC family with a dual-die architecture: SoC0 ("CPU" die with four ARM Cortex-A35 application cores) and SoC1 ("IO" die with peripherals) each SoC have its own SCU PLLs, clock dividers and reset domains. Link: https://lore.kernel.org/r/[email protected]
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/aspeed/Makefile1
-rw-r--r--drivers/clk/aspeed/clk_ast2700.c952
-rw-r--r--drivers/ram/aspeed/Kconfig2
-rw-r--r--drivers/ram/aspeed/Makefile1
-rw-r--r--drivers/ram/aspeed/sdram_ast2700.c15
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-ast2700.c82
-rw-r--r--drivers/spi/spi-aspeed-smc.c219
9 files changed, 1215 insertions, 67 deletions
diff --git a/drivers/clk/aspeed/Makefile b/drivers/clk/aspeed/Makefile
index 84776e5265e..285180b67cf 100644
--- a/drivers/clk/aspeed/Makefile
+++ b/drivers/clk/aspeed/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_ASPEED_AST2500) += clk_ast2500.o
obj-$(CONFIG_ASPEED_AST2600) += clk_ast2600.o
+obj-$(CONFIG_ASPEED_AST2700) += clk_ast2700.o
diff --git a/drivers/clk/aspeed/clk_ast2700.c b/drivers/clk/aspeed/clk_ast2700.c
new file mode 100644
index 00000000000..ca76abef48f
--- /dev/null
+++ b/drivers/clk/aspeed/clk_ast2700.c
@@ -0,0 +1,952 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) ASPEED Technology Inc.
+ */
+
+#include <asm/io.h>
+#include <asm/arch/scu_ast2700.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <syscon.h>
+#include <linux/bitfield.h>
+
+#include <dt-bindings/clock/aspeed,ast2700-scu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * RGMII clock source tree
+ * HPLL -->|\
+ * | |---->| divider |---->RGMII 125M for MAC#0 & MAC#1
+ * APLL -->|/
+ */
+#define RGMII_DEFAULT_CLK_SRC SCU1_CLK_HPLL
+
+struct mac_delay_config {
+ u32 tx_delay_1000;
+ u32 rx_delay_1000;
+ u32 tx_delay_100;
+ u32 rx_delay_100;
+ u32 tx_delay_10;
+ u32 rx_delay_10;
+};
+
+typedef int (*ast2700_clk_init_fn)(struct udevice *dev);
+
+struct ast2700_clk_priv {
+ void __iomem *reg;
+ ast2700_clk_init_fn init;
+};
+
+static u32 ast2700_soc1_get_pll_rate(struct ast2700_scu1 *scu, int pll_idx)
+{
+ union ast2700_pll_reg pll_reg;
+ u32 mul = 1, div = 1;
+
+ switch (pll_idx) {
+ case SCU1_CLK_HPLL:
+ pll_reg.w = readl(&scu->hpll);
+ break;
+ case SCU1_CLK_APLL:
+ pll_reg.w = readl(&scu->apll);
+ break;
+ case SCU1_CLK_DPLL:
+ pll_reg.w = readl(&scu->dpll);
+ break;
+ }
+
+ if (!pll_reg.b.bypass) {
+ mul = (pll_reg.b.m + 1) / (pll_reg.b.n + 1);
+ div = (pll_reg.b.p + 1);
+ }
+
+ return ((CLKIN_25M * mul) / div);
+}
+
+#define SCU_CLKSEL2_HCLK_DIV_MASK GENMASK(22, 20)
+#define SCU_CLKSEL2_HCLK_DIV_SHIFT 20
+
+static u32 ast2700_soc1_get_hclk_rate(struct ast2700_scu1 *scu)
+{
+ u32 rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+ u32 clk_sel2 = readl(&scu->clk_sel2);
+ u32 hclk_div = (clk_sel2 & SCU_CLKSEL2_HCLK_DIV_MASK) >>
+ SCU_CLKSEL2_HCLK_DIV_SHIFT;
+
+ if (!hclk_div)
+ hclk_div = 2;
+ else
+ hclk_div++;
+
+ return (rate / hclk_div);
+}
+
+#define SCU1_CLKSEL1_PCLK_DIV_MASK GENMASK(20, 18)
+#define SCU1_CLKSEL1_PCLK_DIV_SHIFT 18
+
+static u32 ast2700_soc1_get_pclk_rate(struct ast2700_scu1 *scu)
+{
+ u32 rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+
+ u32 clk_sel1 = readl(&scu->clk_sel1);
+ u32 pclk_div = (clk_sel1 & SCU1_CLKSEL1_PCLK_DIV_MASK) >>
+ SCU1_CLKSEL1_PCLK_DIV_SHIFT;
+
+ return (rate / ((pclk_div + 1) * 2));
+}
+
+#define SCU_UART_CLKGEN_N_MASK GENMASK(17, 8)
+#define SCU_UART_CLKGEN_N_SHIFT 8
+#define SCU_UART_CLKGEN_R_MASK GENMASK(7, 0)
+#define SCU_UART_CLKGEN_R_SHIFT 0
+
+static u32 ast2700_soc1_get_uart_uxclk_rate(struct ast2700_scu1 *scu)
+{
+ u32 uxclk_sel = readl(&scu->clk_sel2) & GENMASK(1, 0);
+ u32 uxclk_ctrl = readl(&scu->uxclk_ctrl);
+ u32 rate;
+
+ switch (uxclk_sel) {
+ case 0:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 4;
+ break;
+ case 1:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 2;
+ break;
+ case 2:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL);
+ break;
+ case 3:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+ break;
+ }
+
+ u32 n = (uxclk_ctrl & SCU_UART_CLKGEN_N_MASK) >>
+ SCU_UART_CLKGEN_N_SHIFT;
+ u32 r = (uxclk_ctrl & SCU_UART_CLKGEN_R_MASK) >>
+ SCU_UART_CLKGEN_R_SHIFT;
+
+ return ((rate * r) / (n * 2));
+}
+
+#define SCU_HUART_CLKGEN_N_MASK GENMASK(17, 8)
+#define SCU_HUART_CLKGEN_N_SHIFT 8
+#define SCU_HUART_CLKGEN_R_MASK GENMASK(7, 0)
+#define SCU_HUART_CLKGEN_R_SHIFT 0
+
+static u32 ast2700_soc1_get_uart_huxclk_rate(struct ast2700_scu1 *scu)
+{
+ u32 huxclk_sel = (readl(&scu->clk_sel2) & GENMASK(4, 3)) >> 3;
+ u32 huxclk_ctrl = readl(&scu->huxclk_ctrl);
+ u32 n = (huxclk_ctrl & SCU_HUART_CLKGEN_N_MASK) >>
+ SCU_HUART_CLKGEN_N_SHIFT;
+ u32 r = (huxclk_ctrl & SCU_HUART_CLKGEN_R_MASK) >>
+ SCU_HUART_CLKGEN_R_SHIFT;
+ u32 rate;
+
+ switch (huxclk_sel) {
+ case 0:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 4;
+ break;
+ case 1:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 2;
+ break;
+ case 2:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL);
+ break;
+ case 3:
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+ break;
+ }
+
+ return ((rate * r) / (n * 2));
+}
+
+#define SCU_CLKSRC1_SDIO_DIV_MASK GENMASK(16, 14)
+#define SCU_CLKSRC1_SDIO_DIV_SHIFT 14
+#define SCU_CLKSRC1_SDIO_SEL BIT(13)
+const int ast2700_sd_div_tbl[] = {
+ 2, 2, 3, 4, 5, 6, 7, 8
+};
+
+static u32 ast2700_soc1_get_sdio_clk_rate(struct ast2700_scu1 *scu)
+{
+ u32 rate = 0;
+ u32 clk_sel1 = readl(&scu->clk_sel1);
+ u32 div = (clk_sel1 & SCU_CLKSRC1_SDIO_DIV_MASK) >>
+ SCU_CLKSRC1_SDIO_DIV_SHIFT;
+
+ if (clk_sel1 & SCU_CLKSRC1_SDIO_SEL)
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL);
+ else
+ rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+
+ if (!div)
+ div = 1;
+
+ div++;
+
+ return (rate / div);
+}
+
+static void ast2700_init_sdclk(struct ast2700_scu1 *scu)
+{
+ u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+ u32 reg_280;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (src_clk / ast2700_sd_div_tbl[i] <= 125000000)
+ break;
+ }
+
+ reg_280 = readl(&scu->clk_sel1);
+ reg_280 &= ~(SCU_CLKSRC1_SDIO_DIV_MASK | SCU_CLKSRC1_SDIO_SEL);
+ reg_280 |= i << SCU_CLKSRC1_SDIO_DIV_SHIFT;
+ writel(reg_280, &scu->clk_sel1);
+}
+
+static u32
+ast2700_soc1_get_uart_clk_rate(struct ast2700_scu1 *scu, int uart_idx)
+{
+ u32 rate = 0;
+
+ if (readl(&scu->clk_sel1) & BIT(uart_idx))
+ rate = ast2700_soc1_get_uart_huxclk_rate(scu);
+ else
+ rate = ast2700_soc1_get_uart_uxclk_rate(scu);
+
+ return rate;
+}
+
+static ulong ast2700_soc1_clk_get_rate(struct clk *clk)
+{
+ struct ast2700_clk_priv *priv = dev_get_priv(clk->dev);
+ struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg;
+ ulong rate = 0;
+
+ switch (clk->id) {
+ case SCU1_CLK_HPLL:
+ case SCU1_CLK_APLL:
+ case SCU1_CLK_DPLL:
+ rate = ast2700_soc1_get_pll_rate(scu, clk->id);
+ break;
+ case SCU1_CLK_AHB:
+ rate = ast2700_soc1_get_hclk_rate(scu);
+ break;
+ case SCU1_CLK_APB:
+ rate = ast2700_soc1_get_pclk_rate(scu);
+ break;
+ case SCU1_CLK_GATE_UART0CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 0);
+ break;
+ case SCU1_CLK_GATE_UART1CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 1);
+ break;
+ case SCU1_CLK_GATE_UART2CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 2);
+ break;
+ case SCU1_CLK_GATE_UART3CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 3);
+ break;
+ case SCU1_CLK_GATE_UART5CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 5);
+ break;
+ case SCU1_CLK_GATE_UART6CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 6);
+ break;
+ case SCU1_CLK_GATE_UART7CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 7);
+ break;
+ case SCU1_CLK_GATE_UART8CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 8);
+ break;
+ case SCU1_CLK_GATE_UART9CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 9);
+ break;
+ case SCU1_CLK_GATE_UART10CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 10);
+ break;
+ case SCU1_CLK_GATE_UART11CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 11);
+ break;
+ case SCU1_CLK_GATE_UART12CLK:
+ rate = ast2700_soc1_get_uart_clk_rate(scu, 12);
+ break;
+ case SCU1_CLK_GATE_SDCLK:
+ rate = ast2700_soc1_get_sdio_clk_rate(scu);
+ break;
+ case SCU1_CLK_UXCLK:
+ rate = ast2700_soc1_get_uart_uxclk_rate(scu);
+ break;
+ case SCU1_CLK_HUXCLK:
+ rate = ast2700_soc1_get_uart_huxclk_rate(scu);
+ break;
+ default:
+ debug("%s: unknown clk %ld\n", __func__, clk->id);
+ return -ENOENT;
+ }
+
+ return rate;
+}
+
+static int ast2700_soc1_clk_enable(struct clk *clk)
+{
+ struct ast2700_clk_priv *priv = dev_get_priv(clk->dev);
+ struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg;
+ u32 clkgate_bit;
+
+ if (clk->id >= 32)
+ clkgate_bit = BIT(clk->id - 32);
+ else
+ clkgate_bit = BIT(clk->id);
+
+ writel(clkgate_bit, &scu->clkgate_clr1);
+
+ return 0;
+}
+
+static const struct clk_ops ast2700_soc1_clk_ops = {
+ .get_rate = ast2700_soc1_clk_get_rate,
+ .enable = ast2700_soc1_clk_enable,
+};
+
+#define SCU_HW_REVISION_ID GENMASK(23, 16)
+#define SCU_CPUCLK_MASK GENMASK(4, 2)
+#define SCU_CPUCLK_SHIFT 2
+static u32 ast2700_soc0_get_hpll_rate(struct ast2700_scu0 *scu)
+{
+ u32 chip_id1 = readl(&scu->chip_id1);
+ u32 hwstrap1 = readl(&scu->hwstrap1);
+ union ast2700_pll_reg pll_reg;
+ u32 mul = 1, div = 1;
+ u32 rate;
+
+ pll_reg.w = readl(&scu->hpll);
+
+ if ((chip_id1 & SCU_HW_REVISION_ID) && (hwstrap1 & BIT(3))) {
+ switch ((hwstrap1 & GENMASK(4, 2)) >> 2) {
+ case 2:
+ rate = 1800000000;
+ break;
+ case 3:
+ rate = 1700000000;
+ break;
+ case 6:
+ rate = 1200000000;
+ break;
+ case 7:
+ rate = 800000000;
+ break;
+ default:
+ rate = 1600000000;
+ }
+ } else if (hwstrap1 & GENMASK(3, 2)) {
+ switch ((hwstrap1 & GENMASK(3, 2)) >> 2) {
+ case 1U:
+ rate = 1900000000;
+ break;
+ case 2U:
+ rate = 1800000000;
+ break;
+ case 3U:
+ rate = 1700000000;
+ break;
+ default:
+ rate = 1600000000;
+ break;
+ }
+ } else {
+ if (pll_reg.b.bypass == 0U) {
+ /* F = 25Mhz * [(M + 2) / 2 * (n + 1)] / (p + 1) */
+ mul = (pll_reg.b.m + 1) / ((pll_reg.b.n + 1) * 2);
+ div = (pll_reg.b.p + 1);
+ }
+ rate = ((CLKIN_25M * mul) / div);
+ }
+
+ return rate;
+}
+
+static u32 ast2700_soc0_get_pll_rate(struct ast2700_scu0 *scu, int pll_idx)
+{
+ union ast2700_pll_reg pll_reg;
+ u32 mul = 1, div = 1;
+ u32 rate;
+
+ switch (pll_idx) {
+ case SCU0_CLK_DPLL:
+ pll_reg.w = readl(&scu->dpll);
+ break;
+ case SCU0_CLK_MPLL:
+ pll_reg.w = readl(&scu->mpll);
+ break;
+ default:
+ pr_err("%s: invalid PSP clock source (%d)\n", __func__, pll_idx);
+ return 0;
+ }
+
+ if (pll_reg.b.bypass == 0U) {
+ if (pll_idx == SCU0_CLK_MPLL) {
+ /* F = 25Mhz * [M / (n + 1)] / (p + 1) */
+ mul = (pll_reg.b.m) / ((pll_reg.b.n + 1));
+ div = (pll_reg.b.p + 1);
+ } else {
+ /* F = 25Mhz * [(M + 2) / 2 * (n + 1)] / (p + 1) */
+ mul = (pll_reg.b.m + 1) / ((pll_reg.b.n + 1) * 2);
+ div = (pll_reg.b.p + 1);
+ }
+ }
+
+ rate = ((CLKIN_25M * mul) / div);
+
+ return rate;
+}
+
+/*
+ * AST2700A1
+ * SCU010[4:2]:
+ * 000: CPUCLK=MPLL=1.6GHz (MPLL default setting with SCU310, SCU314)
+ * 001: CPUCLK=HPLL=2.0GHz (HPLL default setting with SCU300, SCU304)
+ * 010: CPUCLK=HPLL=1.8GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304)
+ * 011: CPUCLK=HPLL=1.7GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304)
+ * 100: CPUCLK=MPLL/2=800MHz (MPLL default setting with SCU310, SCU314)
+ * 101: CPUCLK=HPLL/2=1.0GHz (HPLL default setting with SCU300, SCU304)
+ * 110: CPUCLK=HPLL=1.2GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304)
+ * 111: CPUCLK=HPLL=800MHz (HPLL frequency is constance and is not controlled by SCU300, SCU304)
+ */
+
+static u32 ast2700_soc0_get_pspclk_rate(struct ast2700_scu0 *scu)
+{
+ u32 chip_id1 = readl(&scu->chip_id1);
+ u32 hwstrap1 = readl(&scu->hwstrap1);
+ u32 rate;
+ int cpuclk_set;
+
+ if (chip_id1 & SCU_HW_REVISION_ID) {
+ cpuclk_set = (hwstrap1 & SCU_CPUCLK_MASK) >> SCU_CPUCLK_SHIFT;
+ switch (cpuclk_set) {
+ case 0:
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ rate = ast2700_soc0_get_hpll_rate(scu);
+ break;
+ case 4:
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 2;
+ break;
+ case 5:
+ rate = ast2700_soc0_get_hpll_rate(scu) / 2;
+ break;
+ default:
+ rate = ast2700_soc0_get_hpll_rate(scu);
+ break;
+ }
+ } else {
+ if (hwstrap1 & BIT(4))
+ rate = ast2700_soc0_get_hpll_rate(scu);
+ else
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL);
+ }
+ return rate;
+}
+
+static u32 ast2700_soc0_get_axi0clk_rate(struct ast2700_scu0 *scu)
+{
+ return ast2700_soc0_get_pspclk_rate(scu) / 2;
+}
+
+#define SCU_AHB_DIV_MASK GENMASK(6, 5)
+#define SCU_AHB_DIV_SHIFT 5
+static u32 hclk_ast2700a1_div_table[] = {
+ 6, 5, 4, 7,
+};
+
+static u32 ast2700_soc0_get_hclk_rate(struct ast2700_scu0 *scu)
+{
+ u32 hwstrap1 = readl(&scu->hwstrap1);
+ u32 chip_id1 = readl(&scu->chip_id1);
+ u32 src_clk;
+ int div;
+
+ if (chip_id1 & SCU_HW_REVISION_ID) {
+ if (hwstrap1 & BIT(7))
+ src_clk = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL);
+ else
+ src_clk = ast2700_soc0_get_hpll_rate(scu);
+
+ div = (hwstrap1 & SCU_AHB_DIV_MASK) >> SCU_AHB_DIV_SHIFT;
+ div = hclk_ast2700a1_div_table[div];
+ } else {
+ if (hwstrap1 & BIT(7))
+ src_clk = ast2700_soc0_get_hpll_rate(scu);
+ else
+ src_clk = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL);
+
+ div = (hwstrap1 & SCU_AHB_DIV_MASK) >> SCU_AHB_DIV_SHIFT;
+
+ if (!div)
+ div = 4;
+ else
+ div = (div + 1) * 2;
+ }
+ return (src_clk / div);
+}
+
+static u32 ast2700_soc0_get_axi1clk_rate(struct ast2700_scu0 *scu)
+{
+ if (readl(&scu->chip_id1) & SCU_HW_REVISION_ID)
+ return ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4;
+ else
+ return ast2700_soc0_get_hclk_rate(scu);
+}
+
+#define SCU0_CLKSEL1_PCLK_DIV_MASK GENMASK(25, 23)
+#define SCU0_CLKSEL1_PCLK_DIV_SHIFT 23
+
+static u32 ast2700_soc0_get_pclk_rate(struct ast2700_scu0 *scu)
+{
+ u32 rate = ast2700_soc0_get_axi0clk_rate(scu);
+ u32 clksel1 = readl(&scu->clk_sel1);
+ int div;
+
+ div = (clksel1 & SCU0_CLKSEL1_PCLK_DIV_MASK) >>
+ SCU0_CLKSEL1_PCLK_DIV_SHIFT;
+
+ return (rate / ((div + 1) * 2));
+}
+
+#define SCU_CLKSEL1_MPHYCLK_SEL_MASK GENMASK(19, 18)
+#define SCU_CLKSEL1_MPHYCLK_SEL_SHIFT 18
+#define SCU_CLKSEL1_MPHYCLK_DIV_MASK GENMASK(7, 0)
+static u32 ast2700_soc0_get_mphyclk_rate(struct ast2700_scu0 *scu)
+{
+ int div = readl(&scu->mphyclk_para) & SCU_CLKSEL1_MPHYCLK_DIV_MASK;
+ u32 chip_id1 = readl(&scu->chip_id1);
+ u32 clk_sel2;
+ int clk_sel;
+ u32 rate = 0;
+
+ if (chip_id1 & SCU_HW_REVISION_ID) {
+ clk_sel2 = readl(&scu->clk_sel2);
+ clk_sel = (clk_sel2 & SCU_CLKSEL1_MPHYCLK_SEL_MASK)
+ >> SCU_CLKSEL1_MPHYCLK_SEL_SHIFT;
+ switch (clk_sel) {
+ case 0:
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL);
+ break;
+ case 1:
+ rate = ast2700_soc0_get_hpll_rate(scu);
+ break;
+ case 2:
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_DPLL);
+ break;
+ case 3:
+ rate = 26000000;
+ break;
+ }
+ } else {
+ rate = ast2700_soc0_get_hpll_rate(scu);
+ }
+
+ return (rate / (div + 1));
+}
+
+static void ast2700_mphy_clk_init(struct ast2700_scu0 *scu)
+{
+ u32 clksrc1, rate = 0;
+ int i;
+
+ /* set mphy clk */
+ if (readl(&scu->chip_id1) & SCU_HW_REVISION_ID) {
+ clksrc1 = (readl(&scu->clk_sel2) & SCU_CLKSEL1_MPHYCLK_SEL_MASK)
+ >> SCU_CLKSEL1_MPHYCLK_SEL_SHIFT;
+ switch (clksrc1) {
+ case 0:
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL);
+ break;
+ case 1:
+ rate = ast2700_soc0_get_hpll_rate(scu);
+ break;
+ case 2:
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_DPLL);
+ break;
+ case 3:
+ rate = 26000000;
+ break;
+ }
+ } else {
+ rate = ast2700_soc0_get_hpll_rate(scu);
+ }
+
+ for (i = 1; i < 256; i++) {
+ if ((rate / i) <= 26000000)
+ break;
+ }
+
+ /* register defined the value plus 1 is divider*/
+ i--;
+ writel(i, &scu->mphyclk_para);
+}
+
+#define SCU_CLKSRC1_EMMC_DIV_MASK GENMASK(14, 12)
+#define SCU_CLKSRC1_EMMC_DIV_SHIFT 12
+#define SCU_CLKSRC1_EMMC_SEL BIT(11)
+static u32 ast2700_soc0_get_emmcclk_rate(struct ast2700_scu0 *scu)
+{
+ u32 clksel1 = readl(&scu->clk_sel1);
+ u32 rate;
+ int div;
+
+ div = (clksel1 & SCU_CLKSRC1_EMMC_DIV_MASK) >> SCU_CLKSRC1_EMMC_DIV_SHIFT;
+
+ if (clksel1 & SCU_CLKSRC1_EMMC_SEL)
+ rate = ast2700_soc0_get_hpll_rate(scu) / 4;
+ else
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4;
+
+ return (rate / ((div + 1) * 2));
+}
+
+static void ast2700_emmc_init(struct ast2700_scu0 *scu)
+{
+ u32 clksrc1, rate, div;
+ int i;
+
+ /* set clk/cmd driving */
+ writel(2, &scu->gpio18d0_ioctrl); /* clk driving */
+ writel(1, &scu->gpio18d1_ioctrl); /* cmd driving */
+ writel(1, &scu->gpio18d2_ioctrl); /* data0 driving */
+ writel(1, &scu->gpio18d3_ioctrl); /* data1 driving */
+ writel(1, &scu->gpio18d4_ioctrl); /* data2 driving */
+ writel(1, &scu->gpio18d5_ioctrl); /* data2 driving */
+
+ /* emmc clk: set clk src mpll/4:400Mhz */
+ clksrc1 = readl(&scu->clk_sel1);
+ rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4;
+ for (i = 0; i < 8; i++) {
+ div = (i + 1) * 2;
+ if ((rate / div) <= 200000000)
+ break;
+ }
+
+ clksrc1 &= ~(SCU_CLKSRC1_EMMC_DIV_MASK | SCU_CLKSRC1_EMMC_SEL);
+ clksrc1 |= (i << SCU_CLKSRC1_EMMC_DIV_SHIFT);
+ writel(clksrc1, &scu->clk_sel1);
+}
+
+static void ast2700_vga_clk_init(struct ast2700_scu0 *scu)
+{
+ if ((readl(&scu->chip_id1) & SCU_HW_REVISION_ID) == 0)
+ return;
+
+ // Use d0clk/d1clk which generated from hpll for vga0/1 after A0
+ // Use CRT1clk as soc display source
+ setbits_le32(&scu->clk_sel3, BIT(14) | BIT(13) | BIT(12));
+}
+
+static u32 ast2700_soc0_get_uartclk_rate(struct ast2700_scu0 *scu)
+{
+ u32 clksel2 = readl(&scu->clk_sel2);
+ u32 div = 1;
+ u32 rate;
+
+ if (clksel2 & BIT(15))
+ rate = 192000000;
+ else
+ rate = 24000000;
+
+ if (clksel2 & BIT(30))
+ div = 13;
+ return (rate / div);
+}
+
+static ulong ast2700_soc0_clk_get_rate(struct clk *clk)
+{
+ struct ast2700_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong rate = 0;
+
+ switch (clk->id) {
+ case SCU0_CLK_PSP:
+ rate = ast2700_soc0_get_pspclk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_HPLL:
+ rate = ast2700_soc0_get_hpll_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_DPLL:
+ case SCU0_CLK_MPLL:
+ rate = ast2700_soc0_get_pll_rate((struct ast2700_scu0 *)priv->reg, clk->id);
+ break;
+ case SCU0_CLK_AXI0:
+ rate = ast2700_soc0_get_axi0clk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_AXI1:
+ rate = ast2700_soc0_get_axi1clk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_AHB:
+ rate = ast2700_soc0_get_hclk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_APB:
+ rate = ast2700_soc0_get_pclk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_GATE_EMMCCLK:
+ rate = ast2700_soc0_get_emmcclk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_GATE_UART4CLK:
+ rate = ast2700_soc0_get_uartclk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ case SCU0_CLK_MPHY:
+ rate = ast2700_soc0_get_mphyclk_rate((struct ast2700_scu0 *)priv->reg);
+ break;
+ default:
+ debug("%s: unknown clk %ld\n", __func__, clk->id);
+ return -ENOENT;
+ }
+
+ return rate;
+}
+
+static int ast2700_soc0_clk_enable(struct clk *clk)
+{
+ struct ast2700_clk_priv *priv = dev_get_priv(clk->dev);
+ struct ast2700_scu0 *scu = (struct ast2700_scu0 *)priv->reg;
+ u32 clkgate_bit = BIT(clk->id);
+
+ writel(clkgate_bit, &scu->clkgate_clr);
+
+ return 0;
+}
+
+static const struct clk_ops ast2700_soc0_clk_ops = {
+ .get_rate = ast2700_soc0_clk_get_rate,
+ .enable = ast2700_soc0_clk_enable,
+};
+
+static void ast2700_init_mac_clk(struct ast2700_scu1 *scu)
+{
+ u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+ u32 reg_280;
+ u8 div_idx;
+
+ /* The MAC source clock selects HPLL only, and the default clock
+ * setting is 200 Mhz.
+ * Calculate the corresponding divider:
+ * 1: div 2
+ * 2: div 3
+ * ...
+ * 7: div 8
+ */
+ for (div_idx = 1; div_idx <= 7; div_idx++)
+ if (DIV_ROUND_UP(src_clk, div_idx + 1) == 200000000)
+ break;
+
+ if (div_idx == 8) {
+ pr_err("MAC clock cannot divide to 200 MHz\n");
+ return;
+ }
+
+ /* set HPLL clock divider */
+ reg_280 = readl(&scu->clk_sel1);
+ reg_280 &= ~GENMASK(31, 29);
+ reg_280 |= div_idx << 29;
+ writel(reg_280, &scu->clk_sel1);
+}
+
+static void ast2700_init_rgmii_clk(struct ast2700_scu1 *scu)
+{
+ u32 reg_284 = readl(&scu->clk_sel2);
+ u32 src_clk = ast2700_soc1_get_pll_rate(scu, RGMII_DEFAULT_CLK_SRC);
+
+ if (RGMII_DEFAULT_CLK_SRC == SCU1_CLK_HPLL) {
+ u32 reg_280;
+ u8 div_idx;
+
+ /* Calculate the corresponding divider:
+ * 1: div 4
+ * 2: div 6
+ * ...
+ * 7: div 16
+ */
+ for (div_idx = 1; div_idx <= 7; div_idx++) {
+ u8 div = 4 + 2 * (div_idx - 1);
+
+ if (DIV_ROUND_UP(src_clk, div) == 125000000)
+ break;
+ }
+ if (div_idx == 8) {
+ pr_err("RGMII using HPLL cannot divide to 125 MHz\n");
+ return;
+ }
+
+ /* set HPLL clock divider */
+ reg_280 = readl(&scu->clk_sel1);
+ reg_280 &= ~GENMASK(27, 25);
+ reg_280 |= div_idx << 25;
+ writel(reg_280, &scu->clk_sel1);
+
+ /* select HPLL clock source */
+ reg_284 &= ~BIT(18);
+ } else {
+ /* APLL clock divider is fixed to 8 */
+ if (DIV_ROUND_UP(src_clk, 8) != 125000000) {
+ pr_err("RGMII using APLL cannot divide to 125 MHz\n");
+ return;
+ }
+
+ /* select APLL clock source */
+ reg_284 |= BIT(18);
+ }
+
+ writel(reg_284, &scu->clk_sel2);
+}
+
+static void ast2700_init_rmii_clk(struct ast2700_scu1 *scu)
+{
+ u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL);
+ u32 reg_280;
+ u8 div_idx;
+
+ /* The RMII source clock selects HPLL only.
+ * Calculate the corresponding divider:
+ * 1: div 8
+ * 2: div 12
+ * ...
+ * 7: div 32
+ */
+ for (div_idx = 1; div_idx <= 7; div_idx++) {
+ u8 div = 8 + 4 * (div_idx - 1);
+
+ if (DIV_ROUND_UP(src_clk, div) == 50000000)
+ break;
+ }
+ if (div_idx == 8) {
+ pr_err("RMII using HPLL cannot divide to 50 MHz\n");
+ return;
+ }
+
+ /* set RMII clock divider */
+ reg_280 = readl(&scu->clk_sel1);
+ reg_280 &= ~GENMASK(23, 21);
+ reg_280 |= div_idx << 21;
+ writel(reg_280, &scu->clk_sel1);
+}
+
+static void ast2700_init_spi(struct ast2700_scu1 *scu)
+{
+ writel(readl(&scu->io_driving8) | 0x0000aaaa, &scu->io_driving8); /* fwspi driving */
+ writel(readl(&scu->io_driving3) | 0x00000aaa, &scu->io_driving3); /* spi0 driving */
+ writel(readl(&scu->io_driving3) | 0x0aaa0000, &scu->io_driving3); /* spi1 driving */
+ writel(readl(&scu->io_driving4) | 0x00002aaa, &scu->io_driving4); /* spi2 driving */
+}
+
+#define SCU1_CLK_I3C_DIV_MASK GENMASK(25, 23)
+#define SCU1_CLK_I3C_DIV(n) ((n) - 1)
+static void ast2700_init_i3c_clk(struct ast2700_scu1 *scu)
+{
+ u32 reg_284;
+
+ /* I3C 250MHz = HPLL/4 */
+ reg_284 = readl(&scu->clk_sel2);
+ reg_284 &= ~SCU1_CLK_I3C_DIV_MASK;
+ reg_284 |= FIELD_PREP(SCU1_CLK_I3C_DIV_MASK, SCU1_CLK_I3C_DIV(4));
+ writel(reg_284, &scu->clk_sel2);
+}
+
+static int ast2700_clk1_init(struct udevice *dev)
+{
+ struct ast2700_clk_priv *priv = dev_get_priv(dev);
+ struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg;
+
+ ast2700_init_spi(scu);
+ ast2700_init_mac_clk(scu);
+ ast2700_init_rgmii_clk(scu);
+ ast2700_init_rmii_clk(scu);
+ ast2700_init_sdclk(scu);
+ ast2700_init_i3c_clk(scu);
+
+ return 0;
+}
+
+static int ast2700_clk0_init(struct udevice *dev)
+{
+ struct ast2700_clk_priv *priv = dev_get_priv(dev);
+ struct ast2700_scu0 *scu = (struct ast2700_scu0 *)priv->reg;
+
+ ast2700_emmc_init(scu);
+ ast2700_mphy_clk_init(scu);
+ ast2700_vga_clk_init(scu);
+
+ return 0;
+}
+
+static int ast2700_clk_probe(struct udevice *dev)
+{
+ struct ast2700_clk_priv *priv = dev_get_priv(dev);
+
+ priv->init = (ast2700_clk_init_fn)dev_get_driver_data(dev);
+ priv->reg = (void __iomem *)dev_read_addr_ptr(dev);
+
+ if (priv->init)
+ return priv->init(dev);
+
+ return 0;
+}
+
+static int ast2700_clk_bind(struct udevice *dev)
+{
+ struct udevice *sysreset_dev, *rst_dev;
+ int ret;
+
+ /* The system reset driver does not have a device node, so bind it here */
+ ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &sysreset_dev);
+ if (ret)
+ debug("Warning: No sysreset driver: ret = %d\n", ret);
+
+ /* Bind the per-SCU reset controller to the same ofnode so that
+ * <&syscon0/1 RESET_X> phandle references resolve to a UCLASS_RESET
+ * device. This pairs with the airoha-style binding pattern.
+ */
+ if (CONFIG_IS_ENABLED(RESET_AST2700)) {
+ ret = device_bind_driver_to_node(dev, "ast2700_reset", "reset",
+ dev_ofnode(dev), &rst_dev);
+ if (ret)
+ debug("Warning: failed to bind reset controller: ret = %d\n", ret);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id ast2700_soc1_clk_ids[] = {
+ { .compatible = "aspeed,ast2700-scu1", .data = (ulong)&ast2700_clk1_init },
+ { },
+};
+
+U_BOOT_DRIVER(aspeed_ast2700_soc1_clk) = {
+ .name = "aspeed_ast2700_scu1",
+ .id = UCLASS_CLK,
+ .of_match = ast2700_soc1_clk_ids,
+ .priv_auto = sizeof(struct ast2700_clk_priv),
+ .ops = &ast2700_soc1_clk_ops,
+ .probe = ast2700_clk_probe,
+ .bind = ast2700_clk_bind,
+};
+
+static const struct udevice_id ast2700_soc0_clk_ids[] = {
+ { .compatible = "aspeed,ast2700-scu0", .data = (ulong)&ast2700_clk0_init },
+ { },
+};
+
+U_BOOT_DRIVER(aspeed_ast2700_soc0_clk) = {
+ .name = "aspeed_ast2700_scu0",
+ .id = UCLASS_CLK,
+ .of_match = ast2700_soc0_clk_ids,
+ .priv_auto = sizeof(struct ast2700_clk_priv),
+ .ops = &ast2700_soc0_clk_ops,
+ .probe = ast2700_clk_probe,
+ .bind = ast2700_clk_bind,
+};
diff --git a/drivers/ram/aspeed/Kconfig b/drivers/ram/aspeed/Kconfig
index 023444b700c..fa5c890bb7a 100644
--- a/drivers/ram/aspeed/Kconfig
+++ b/drivers/ram/aspeed/Kconfig
@@ -77,7 +77,7 @@ choice
prompt "AST2700 DDR target date rate"
default ASPEED_DDR_3200
depends on ASPEED_RAM
- depends on TARGET_ASPEED_AST2700_IBEX
+ depends on ASPEED_AST2700 || TARGET_ASPEED_AST2700_IBEX
config ASPEED_DDR_1600
bool "1600 Mbps"
diff --git a/drivers/ram/aspeed/Makefile b/drivers/ram/aspeed/Makefile
index 1f0b22c8e9f..d29e2154ce9 100644
--- a/drivers/ram/aspeed/Makefile
+++ b/drivers/ram/aspeed/Makefile
@@ -2,4 +2,5 @@
#
obj-$(CONFIG_ASPEED_AST2500) += sdram_ast2500.o
obj-$(CONFIG_ASPEED_AST2600) += sdram_ast2600.o
+obj-$(CONFIG_ASPEED_AST2700) += sdram_ast2700.o
obj-$(CONFIG_TARGET_ASPEED_AST2700_IBEX) += sdram_ast2700.o
diff --git a/drivers/ram/aspeed/sdram_ast2700.c b/drivers/ram/aspeed/sdram_ast2700.c
index 00974da52bb..8605a92abb2 100644
--- a/drivers/ram/aspeed/sdram_ast2700.c
+++ b/drivers/ram/aspeed/sdram_ast2700.c
@@ -14,6 +14,11 @@
#include <linux/sizes.h>
#include <ram.h>
+__weak int fmc_hdr_get_prebuilt(u32 type, u32 *ofst, u32 *size)
+{
+ return -ENOSYS;
+}
+
enum ddr_type {
DDR4_1600 = 0x0,
DDR4_2400,
@@ -128,13 +133,13 @@ static size_t ast2700_sdrammc_get_vga_mem_size(struct sdrammc *sdrammc)
reg = readl(scu0 + SCU0_PCI_MISC70);
if (reg & SCU0_PCI_MISC70_EN_PCIEVGA0) {
- debug("VGA0:%dMB\n", vga_memsz[sel] / SZ_1M);
+ debug("VGA0:%zuMB\n", vga_memsz[sel] / SZ_1M);
dual++;
}
reg = readl(scu0 + SCU0_PCI_MISC80);
if (reg & SCU0_PCI_MISC80_EN_PCIEVGA1) {
- debug("VGA1:%dMB\n", vga_memsz[sel] / SZ_1M);
+ debug("VGA1:%zuMB\n", vga_memsz[sel] / SZ_1M);
dual++;
}
@@ -560,7 +565,7 @@ void dwc_get_mailbox(struct sdrammc *sdrammc, const int mode, u32 *mbox)
dwc_ddrphy_apb_wr(0xd0031, 1);
}
-uint32_t dwc_readMsgBlock(struct sdrammc *sdrammc, const u32 addr_half)
+u32 dwc_readMsgBlock(struct sdrammc *sdrammc, const u32 addr_half)
{
u32 data_word;
@@ -727,7 +732,7 @@ int dwc_ddrphy_phyinit_userCustom_D_loadIMEM(struct sdrammc *sdrammc, const int
fmc_hdr_get_prebuilt(pb_type, &imem_ofst, &imem_size);
memcpy(sdrammc->phy + (DWC_PHY_IMEM_OFST << 1),
- (void *)(0x20000000 + imem_ofst), imem_size);
+ (void *)(uintptr_t)(0x20000000 + imem_ofst), imem_size);
return 0;
}
@@ -746,7 +751,7 @@ int dwc_ddrphy_phyinit_userCustom_F_loadDMEM(struct sdrammc *sdrammc,
fmc_hdr_get_prebuilt(pb_type, &dmem_ofst, &dmem_size);
memcpy(sdrammc->phy + (DWC_PHY_DMEM_OFST << 1),
- (void *)(0x20000000 + dmem_ofst), dmem_size);
+ (void *)(uintptr_t)(0x20000000 + dmem_ofst), dmem_size);
return 0;
}
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index e7c0870c918..c851354c7a5 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -107,6 +107,15 @@ config RESET_AST2600
Say Y if you want to control reset signals of different peripherals
through System Control Unit (SCU).
+config RESET_AST2700
+ bool "Reset controller driver for AST2700 SoCs"
+ depends on DM_RESET && ASPEED_AST2700
+ default y if ASPEED_AST2700
+ help
+ Support for reset controller on AST2700 SoC.
+ Say Y if you want to control reset signals of different peripherals
+ through System Control Unit (SCU).
+
config RESET_ROCKCHIP
bool "Reset controller driver for Rockchip SoCs"
depends on DM_RESET && ARCH_ROCKCHIP && CLK
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 2c83f858895..3fce96509cd 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_AST2500) += reset-ast2500.o
obj-$(CONFIG_RESET_AST2600) += reset-ast2600.o
+obj-$(CONFIG_RESET_AST2700) += reset-ast2700.o
obj-$(CONFIG_$(PHASE_)RESET_ROCKCHIP) += reset-rockchip.o rst-rk3506.o rst-rk3528.o rst-rk3576.o rst-rk3588.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
diff --git a/drivers/reset/reset-ast2700.c b/drivers/reset/reset-ast2700.c
new file mode 100644
index 00000000000..2dd9e36cc0a
--- /dev/null
+++ b/drivers/reset/reset-ast2700.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) ASPEED Technology Inc.
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/err.h>
+#include <reset.h>
+#include <reset-uclass.h>
+
+/* Offset of the modrst register block within the SCU. */
+#define AST2700_RESET_OFFSET 0x200
+
+struct ast2700_reset_priv {
+ void __iomem *base;
+};
+
+static int ast2700_reset_assert(struct reset_ctl *reset_ctl)
+{
+ struct ast2700_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+
+ if (reset_ctl->id < 32)
+ writel(BIT(reset_ctl->id), priv->base);
+ else
+ writel(BIT(reset_ctl->id - 32), priv->base + 0x20);
+
+ return 0;
+}
+
+static int ast2700_reset_deassert(struct reset_ctl *reset_ctl)
+{
+ struct ast2700_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+
+ if (reset_ctl->id < 32)
+ writel(BIT(reset_ctl->id), priv->base + 0x04);
+ else
+ writel(BIT(reset_ctl->id - 32), priv->base + 0x24);
+
+ return 0;
+}
+
+static int ast2700_reset_status(struct reset_ctl *reset_ctl)
+{
+ struct ast2700_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int status;
+
+ if (reset_ctl->id < 32)
+ status = BIT(reset_ctl->id) & readl(priv->base);
+ else
+ status = BIT(reset_ctl->id - 32) & readl(priv->base + 0x20);
+
+ return !!status;
+}
+
+static int ast2700_reset_probe(struct udevice *dev)
+{
+ struct ast2700_reset_priv *priv = dev_get_priv(dev);
+ void __iomem *scu_base;
+
+ scu_base = dev_read_addr_ptr(dev);
+ if (!scu_base)
+ return -EINVAL;
+
+ priv->base = scu_base + AST2700_RESET_OFFSET;
+
+ return 0;
+}
+
+static const struct reset_ops ast2700_reset_ops = {
+ .rst_assert = ast2700_reset_assert,
+ .rst_deassert = ast2700_reset_deassert,
+ .rst_status = ast2700_reset_status,
+};
+
+U_BOOT_DRIVER(ast2700_reset) = {
+ .name = "ast2700_reset",
+ .id = UCLASS_RESET,
+ .probe = ast2700_reset_probe,
+ .ops = &ast2700_reset_ops,
+ .priv_auto = sizeof(struct ast2700_reset_priv),
+};
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index ca29cfd7c88..0186b01ad9a 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -53,18 +53,20 @@ struct aspeed_spi_regs {
u32 dma_len; /* 0x8c DMA Length Register */
u32 dma_checksum; /* 0x90 Checksum Calculation Result */
u32 timings[ASPEED_SPI_MAX_CS]; /* 0x94 Read Timing Compensation */
+ u32 _reserved3[83]; /* 0xA8 - 0x1F0 */
+ u32 val_kept_wdt; /* 0x1F4 Value Kept WDT */
};
struct aspeed_spi_plat {
u8 max_cs;
- void __iomem *ahb_base; /* AHB address base for all flash devices. */
+ uintptr_t ahb_base; /* AHB address base for all flash devices. */
fdt_size_t ahb_sz; /* Overall AHB window size for all flash device. */
u32 hclk_rate; /* AHB clock rate */
};
struct aspeed_spi_flash {
- void __iomem *ahb_base;
- u32 ahb_decoded_sz;
+ uintptr_t ahb_base;
+ size_t ahb_decoded_sz;
u32 ce_ctrl_user;
u32 ce_ctrl_read;
u32 max_freq;
@@ -84,9 +86,9 @@ struct aspeed_spi_info {
u32 min_decoded_sz;
u32 clk_ctrl_mask;
void (*set_4byte)(struct udevice *bus, u32 cs);
- u32 (*segment_start)(struct udevice *bus, u32 reg);
- u32 (*segment_end)(struct udevice *bus, u32 reg);
- u32 (*segment_reg)(u32 start, u32 end);
+ uintptr_t (*segment_start)(struct udevice *bus, u32 reg);
+ uintptr_t (*segment_end)(struct udevice *bus, u32 reg);
+ u32 (*segment_reg)(uintptr_t start, uintptr_t end);
int (*adjust_decoded_sz)(struct udevice *bus);
u32 (*get_clk_setting)(struct udevice *dev, uint hz);
};
@@ -118,30 +120,30 @@ static u32 aspeed_spi_get_io_mode(u32 bus_width)
}
}
-static u32 ast2400_spi_segment_start(struct udevice *bus, u32 reg)
+static uintptr_t ast2400_spi_segment_start(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 start_offset = ((reg >> 16) & 0xff) << 23;
+ uintptr_t start_offset = ((reg >> 16) & 0xff) << 23;
if (start_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + start_offset;
+ return plat->ahb_base + start_offset;
}
-static u32 ast2400_spi_segment_end(struct udevice *bus, u32 reg)
+static uintptr_t ast2400_spi_segment_end(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 end_offset = ((reg >> 24) & 0xff) << 23;
+ uintptr_t end_offset = ((reg >> 24) & 0xff) << 23;
/* Meaningless end_offset, set to physical ahb base. */
if (end_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + end_offset;
+ return plat->ahb_base + end_offset;
}
-static u32 ast2400_spi_segment_reg(u32 start, u32 end)
+static u32 ast2400_spi_segment_reg(uintptr_t start, uintptr_t end)
{
if (start == end)
return 0;
@@ -206,30 +208,30 @@ static u32 ast2400_get_clk_setting(struct udevice *dev, uint max_hz)
return hclk_div;
}
-static u32 ast2500_spi_segment_start(struct udevice *bus, u32 reg)
+static uintptr_t ast2500_spi_segment_start(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 start_offset = ((reg >> 16) & 0xff) << 23;
+ uintptr_t start_offset = ((reg >> 16) & 0xff) << 23;
if (start_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + start_offset;
+ return plat->ahb_base + start_offset;
}
-static u32 ast2500_spi_segment_end(struct udevice *bus, u32 reg)
+static uintptr_t ast2500_spi_segment_end(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 end_offset = ((reg >> 24) & 0xff) << 23;
+ uintptr_t end_offset = ((reg >> 24) & 0xff) << 23;
/* Meaningless end_offset, set to physical ahb base. */
if (end_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + end_offset;
+ return plat->ahb_base + end_offset;
}
-static u32 ast2500_spi_segment_reg(u32 start, u32 end)
+static u32 ast2500_spi_segment_reg(uintptr_t start, uintptr_t end)
{
if (start == end)
return 0;
@@ -346,30 +348,30 @@ end:
return hclk_div;
}
-static u32 ast2600_spi_segment_start(struct udevice *bus, u32 reg)
+static uintptr_t ast2600_spi_segment_start(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 start_offset = (reg << 16) & 0x0ff00000;
+ uintptr_t start_offset = (reg << 16) & 0x0ff00000;
if (start_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + start_offset;
+ return plat->ahb_base + start_offset;
}
-static u32 ast2600_spi_segment_end(struct udevice *bus, u32 reg)
+static uintptr_t ast2600_spi_segment_end(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 end_offset = reg & 0x0ff00000;
+ uintptr_t end_offset = reg & 0x0ff00000;
/* Meaningless end_offset, set to physical ahb base. */
if (end_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + end_offset + 0x100000;
+ return plat->ahb_base + end_offset + 0x100000;
}
-static u32 ast2600_spi_segment_reg(u32 start, u32 end)
+static u32 ast2600_spi_segment_reg(uintptr_t start, uintptr_t end)
{
if (start == end)
return 0;
@@ -473,6 +475,70 @@ static u32 ast2600_get_clk_setting(struct udevice *dev, uint max_hz)
return hclk_div;
}
+static uintptr_t ast2700_spi_segment_start(struct udevice *bus, u32 reg)
+{
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ uintptr_t start_offset = (reg & 0x0000ffff) << 16;
+
+ if (start_offset == 0)
+ return plat->ahb_base;
+
+ return plat->ahb_base + start_offset;
+}
+
+static uintptr_t ast2700_spi_segment_end(struct udevice *bus, u32 reg)
+{
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ uintptr_t end_offset = reg & 0xffff0000;
+
+ /* Meaningless end_offset, set to physical ahb base. */
+ if (end_offset == 0)
+ return plat->ahb_base;
+
+ return plat->ahb_base + end_offset;
+}
+
+static u32 ast2700_spi_segment_reg(uintptr_t start, uintptr_t end)
+{
+ if (start == end)
+ return 0;
+
+ return (((start >> 16) & 0x7fff) | ((end + 1) & 0x7fff0000));
+}
+
+static void ast2700_spi_chip_set_4byte(struct udevice *bus, u32 cs)
+{
+ struct aspeed_spi_priv *priv = dev_get_priv(bus);
+ u32 reg_val;
+
+ reg_val = readl(&priv->regs->ctrl);
+ reg_val |= 0x11 << cs;
+ writel(reg_val, &priv->regs->ctrl);
+
+ reg_val = readl(&priv->regs->val_kept_wdt);
+ reg_val |= (0x11 << 4) << cs;
+ writel(reg_val, &priv->regs->val_kept_wdt);
+}
+
+static int ast2700_adjust_decoded_size(struct udevice *bus)
+{
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ struct aspeed_spi_priv *priv = dev_get_priv(bus);
+ struct aspeed_spi_flash *flashes = &priv->flashes[0];
+ int ret;
+ int cs;
+
+ /* Close unused CS. */
+ for (cs = priv->num_cs; cs < plat->max_cs; cs++)
+ flashes[cs].ahb_decoded_sz = 0;
+
+ ret = aspeed_spi_trim_decoded_size(bus);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
/*
* As the flash size grows up, we need to trim some decoded
* size if needed for the sake of conforming the maximum
@@ -512,12 +578,12 @@ static int aspeed_spi_trim_decoded_size(struct udevice *bus)
return 0;
}
-static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf,
+static int aspeed_spi_read_from_ahb(uintptr_t ahb_base, void *buf,
size_t len)
{
size_t offset = 0;
- if (IS_ALIGNED((uintptr_t)ahb_base, sizeof(uintptr_t)) &&
+ if (IS_ALIGNED(ahb_base, sizeof(uintptr_t)) &&
IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) {
readsl(ahb_base, buf, len >> 2);
offset = len & ~0x3;
@@ -529,12 +595,12 @@ static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf,
return 0;
}
-static int aspeed_spi_write_to_ahb(void __iomem *ahb_base, const void *buf,
+static int aspeed_spi_write_to_ahb(uintptr_t ahb_base, const void *buf,
size_t len)
{
size_t offset = 0;
- if (IS_ALIGNED((uintptr_t)ahb_base, sizeof(uintptr_t)) &&
+ if (IS_ALIGNED(ahb_base, sizeof(uintptr_t)) &&
IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) {
writesl(ahb_base, buf, len >> 2);
offset = len & ~0x3;
@@ -589,7 +655,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave,
struct aspeed_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(slave->dev);
u32 cs = slave_plat->cs[0];
- u32 ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs];
+ uintptr_t ce_ctrl_reg = (uintptr_t)&priv->regs->ce_ctrl[cs];
u32 ce_ctrl_val;
struct aspeed_spi_flash *flash = &priv->flashes[cs];
u8 dummy_data[16] = {0};
@@ -602,7 +668,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave,
op->data.nbytes, op->data.buswidth);
if (priv->info == &ast2400_spi_info)
- ce_ctrl_reg = (u32)&priv->regs->ctrl;
+ ce_ctrl_reg = (uintptr_t)&priv->regs->ctrl;
/*
* Set controller to 4-byte address mode
@@ -670,7 +736,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
u32 i;
u32 cs = slave_plat->cs[0];
u32 cmd_io_conf;
- u32 ce_ctrl_reg;
+ uintptr_t ce_ctrl_reg;
if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) {
/*
@@ -681,9 +747,9 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
return -EOPNOTSUPP;
}
- ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs];
+ ce_ctrl_reg = (uintptr_t)&priv->regs->ce_ctrl[cs];
if (info == &ast2400_spi_info)
- ce_ctrl_reg = (u32)&priv->regs->ctrl;
+ ce_ctrl_reg = (uintptr_t)&priv->regs->ctrl;
if (desc->info.length > 0x1000000)
priv->info->set_4byte(bus, cs);
@@ -693,7 +759,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
priv->flashes[cs].ahb_decoded_sz = desc->info.length;
for (i = 0; i < priv->num_cs; i++) {
- dev_dbg(dev, "cs: %d, sz: 0x%x\n", i,
+ dev_dbg(dev, "cs: %d, sz: 0x%zx\n", i,
priv->flashes[cs].ahb_decoded_sz);
}
@@ -728,7 +794,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
u32 cs = slave_plat->cs[0];
int ret;
- dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%x\n",
+ dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%zx\n",
desc->info.op_tmpl.cmd.opcode, offs, len);
if (priv->flashes[cs].ahb_decoded_sz < offs + len ||
@@ -738,7 +804,10 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
if (ret != 0)
return 0;
} else {
- memcpy_fromio(buf, priv->flashes[cs].ahb_base + offs, len);
+ memcpy_fromio(buf,
+ (void __iomem *)(priv->flashes[cs].ahb_base +
+ (uintptr_t)offs),
+ len);
}
return len;
@@ -783,19 +852,19 @@ static void aspeed_spi_decoded_range_set(struct udevice *bus)
struct aspeed_spi_plat *plat = dev_get_plat(bus);
struct aspeed_spi_priv *priv = dev_get_priv(bus);
u32 decoded_reg_val;
- u32 start_addr, end_addr;
+ uintptr_t start_addr, end_addr;
u32 cs;
for (cs = 0; cs < plat->max_cs; cs++) {
- start_addr = (u32)priv->flashes[cs].ahb_base;
- end_addr = (u32)priv->flashes[cs].ahb_base +
+ start_addr = priv->flashes[cs].ahb_base;
+ end_addr = priv->flashes[cs].ahb_base +
priv->flashes[cs].ahb_decoded_sz;
decoded_reg_val = priv->info->segment_reg(start_addr, end_addr);
writel(decoded_reg_val, &priv->regs->segment_addr[cs]);
- dev_dbg(bus, "cs: %d, decoded_reg: 0x%x, start: 0x%x, end: 0x%x\n",
+ dev_dbg(bus, "cs: %d, decoded_reg: 0x%x, start: 0x%lx, end: 0x%lx\n",
cs, decoded_reg_val, start_addr, end_addr);
}
}
@@ -851,13 +920,13 @@ static int aspeed_spi_decoded_ranges_sanity(struct udevice *bus)
* address base are monotonic increasing with CE#.
*/
for (cs = plat->max_cs - 1; cs > 0; cs--) {
- if ((u32)priv->flashes[cs].ahb_base != 0 &&
- (u32)priv->flashes[cs].ahb_base <
- (u32)priv->flashes[cs - 1].ahb_base +
+ if (priv->flashes[cs].ahb_base != 0 &&
+ priv->flashes[cs].ahb_base <
+ priv->flashes[cs - 1].ahb_base +
priv->flashes[cs - 1].ahb_decoded_sz) {
- dev_err(bus, "decoded range overlay 0x%08x 0x%08x\n",
- (u32)priv->flashes[cs].ahb_base,
- (u32)priv->flashes[cs - 1].ahb_base);
+ dev_err(bus, "decoded range overlay 0x%08lx 0x%08lx\n",
+ priv->flashes[cs].ahb_base,
+ priv->flashes[cs - 1].ahb_base);
return -EINVAL;
}
}
@@ -895,14 +964,13 @@ static int aspeed_spi_read_fixed_decoded_ranges(struct udevice *bus)
return ret;
for (i = 0; i < count; i++) {
- priv->flashes[ranges[i].cs].ahb_base =
- (void __iomem *)ranges[i].ahb_base;
+ priv->flashes[ranges[i].cs].ahb_base = ranges[i].ahb_base;
priv->flashes[ranges[i].cs].ahb_decoded_sz =
ranges[i].sz;
}
for (i = 0; i < plat->max_cs; i++) {
- dev_dbg(bus, "ahb_base: 0x%p, size: 0x%08x\n",
+ dev_dbg(bus, "ahb_base: 0x%lx, size: 0x%08zx\n",
priv->flashes[i].ahb_base,
priv->flashes[i].ahb_decoded_sz);
}
@@ -1063,6 +1131,32 @@ static const struct aspeed_spi_info ast2600_spi_info = {
.get_clk_setting = ast2600_get_clk_setting,
};
+static const struct aspeed_spi_info ast2700_fmc_info = {
+ .io_mode_mask = 0xf0000000,
+ .max_bus_width = 4,
+ .min_decoded_sz = 0x10000,
+ .clk_ctrl_mask = 0x0f000f00,
+ .set_4byte = ast2700_spi_chip_set_4byte,
+ .segment_start = ast2700_spi_segment_start,
+ .segment_end = ast2700_spi_segment_end,
+ .segment_reg = ast2700_spi_segment_reg,
+ .adjust_decoded_sz = ast2700_adjust_decoded_size,
+ .get_clk_setting = ast2600_get_clk_setting,
+};
+
+static const struct aspeed_spi_info ast2700_spi_info = {
+ .io_mode_mask = 0xf0000000,
+ .max_bus_width = 4,
+ .min_decoded_sz = 0x10000,
+ .clk_ctrl_mask = 0x0f000f00,
+ .set_4byte = ast2700_spi_chip_set_4byte,
+ .segment_start = ast2700_spi_segment_start,
+ .segment_end = ast2700_spi_segment_end,
+ .segment_reg = ast2700_spi_segment_reg,
+ .adjust_decoded_sz = ast2700_adjust_decoded_size,
+ .get_clk_setting = ast2600_get_clk_setting,
+};
+
static int aspeed_spi_claim_bus(struct udevice *dev)
{
struct udevice *bus = dev->parent;
@@ -1129,7 +1223,8 @@ static int apseed_spi_of_to_plat(struct udevice *bus)
return -EINVAL;
}
- plat->ahb_base = devfdt_get_addr_size_index_ptr(bus, 1, &plat->ahb_sz);
+ plat->ahb_base =
+ (uintptr_t)devfdt_get_addr_size_index_ptr(bus, 1, &plat->ahb_sz);
if (!plat->ahb_base) {
dev_err(bus, "wrong AHB base\n");
return -EINVAL;
@@ -1147,8 +1242,8 @@ static int apseed_spi_of_to_plat(struct udevice *bus)
plat->hclk_rate = clk_get_rate(&hclk);
- dev_dbg(bus, "ctrl_base = 0x%x, ahb_base = 0x%p, size = 0x%llx\n",
- (u32)priv->regs, plat->ahb_base, (fdt64_t)plat->ahb_sz);
+ dev_dbg(bus, "ctrl_base = 0x%p, ahb_base = 0x%lx, size = 0x%llx\n",
+ priv->regs, plat->ahb_base, (fdt64_t)plat->ahb_sz);
dev_dbg(bus, "hclk = %dMHz, max_cs = %d\n",
plat->hclk_rate / 1000000, plat->max_cs);
@@ -1199,6 +1294,8 @@ static const struct udevice_id aspeed_spi_ids[] = {
{ .compatible = "aspeed,ast2500-spi", .data = (ulong)&ast2500_spi_info, },
{ .compatible = "aspeed,ast2600-fmc", .data = (ulong)&ast2600_fmc_info, },
{ .compatible = "aspeed,ast2600-spi", .data = (ulong)&ast2600_spi_info, },
+ { .compatible = "aspeed,ast2700-fmc", .data = (ulong)&ast2700_fmc_info, },
+ { .compatible = "aspeed,ast2700-spi", .data = (ulong)&ast2700_spi_info, },
{ }
};