diff options
Diffstat (limited to 'drivers')
191 files changed, 4581 insertions, 3564 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 0b0c610e629..fe35e07b124 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -162,6 +162,7 @@ source "drivers/xen/Kconfig" config PHYS_TO_BUS bool "Custom physical to bus address mapping" + depends on !COMPILE_TEST help Some SoCs use a different address map for CPU physical addresses and peripheral DMA master accesses. If yours does, select this option in diff --git a/drivers/adc/meson-saradc.c b/drivers/adc/meson-saradc.c index 60e348968fb..0144ff828c5 100644 --- a/drivers/adc/meson-saradc.c +++ b/drivers/adc/meson-saradc.c @@ -205,9 +205,9 @@ static int meson_saradc_lock(struct meson_saradc_priv *priv) do { udelay(1); regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); - } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); + } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && --timeout); - if (timeout < 0) { + if (!timeout) { printf("Timeout while waiting for BL30 unlock\n"); return -ETIMEDOUT; } @@ -256,9 +256,9 @@ static int meson_saradc_wait_busy_clear(struct meson_saradc_priv *priv) do { udelay(1); regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); - } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--); + } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && --timeout); - if (timeout < 0) + if (!timeout) return -ETIMEDOUT; return 0; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index c6c148ebd17..185da2b5cfc 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -137,6 +137,7 @@ endif # EFI_MEDIA config IDE bool "Support IDE controllers" + depends on !COMPILE_TEST select BLK help Enables support for IDE (Integrated Drive Electronics) hard drives. diff --git a/drivers/clk/altera/clk-agilex.c b/drivers/clk/altera/clk-agilex.c index 242740a4b00..fdbf834bb2f 100644 --- a/drivers/clk/altera/clk-agilex.c +++ b/drivers/clk/altera/clk-agilex.c @@ -14,6 +14,7 @@ #include <dm/lists.h> #include <dm/util.h> #include <dt-bindings/clock/agilex-clock.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <asm/arch/clock_manager.h> @@ -22,6 +23,8 @@ DECLARE_GLOBAL_DATA_PTR; struct socfpga_clk_plat { void __iomem *regs; + int pllgrp; + int bitmask; }; /* @@ -544,14 +547,11 @@ static u32 clk_get_emac_clk_hz(struct socfpga_clk_plat *plat, u32 emac_id) /* Get EMAC clock source */ ctl = CM_REG_READL(plat, CLKMGR_PERPLL_EMACCTL); if (emac_id == AGILEX_EMAC0_CLK) - ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET) & - CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK; + ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK, ctl); else if (emac_id == AGILEX_EMAC1_CLK) - ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET) & - CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK; + ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK, ctl); else if (emac_id == AGILEX_EMAC2_CLK) - ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_OFFSET) & - CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK; + ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK, ctl); else return 0; @@ -643,8 +643,125 @@ static ulong socfpga_clk_get_rate(struct clk *clk) } } +static int bitmask_from_clk_id(struct clk *clk) +{ + struct socfpga_clk_plat *plat = dev_get_plat(clk->dev); + + switch (clk->id) { + case AGILEX_MPU_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_MPUCLK_MASK; + break; + case AGILEX_L4_MAIN_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4MAINCLK_MASK; + break; + case AGILEX_L4_MP_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK; + break; + case AGILEX_L4_SP_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4SPCLK_MASK; + break; + case AGILEX_CS_AT_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK; + break; + case AGILEX_CS_TRACE_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK; + break; + case AGILEX_CS_PDBG_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK; + break; + case AGILEX_CS_TIMER_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSTIMERCLK_MASK; + break; + case AGILEX_S2F_USER0_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK; + break; + case AGILEX_EMAC0_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC0CLK_MASK; + break; + case AGILEX_EMAC1_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC1CLK_MASK; + break; + case AGILEX_EMAC2_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC2CLK_MASK; + break; + case AGILEX_EMAC_PTP_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMACPTPCLK_MASK; + break; + case AGILEX_GPIO_DB_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_GPIODBCLK_MASK; + break; + case AGILEX_SDMMC_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK; + break; + case AGILEX_S2F_USER1_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_S2FUSER1CLK_MASK; + break; + case AGILEX_PSI_REF_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_PSIREFCLK_MASK; + break; + case AGILEX_USB_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_USBCLK_MASK; + break; + case AGILEX_SPI_M_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_SPIMCLK_MASK; + break; + case AGILEX_NAND_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_NANDCLK_MASK; + break; + default: + return -ENXIO; + } + + return 0; +} + static int socfpga_clk_enable(struct clk *clk) { + struct socfpga_clk_plat *plat = dev_get_plat(clk->dev); + uintptr_t base_addr = (uintptr_t)plat->regs; + int ret; + + ret = bitmask_from_clk_id(clk); + if (ret) + return ret; + + setbits_le32(base_addr + plat->pllgrp, plat->bitmask); + + return 0; +} + +static int socfpga_clk_disable(struct clk *clk) +{ + struct socfpga_clk_plat *plat = dev_get_plat(clk->dev); + uintptr_t base_addr = (uintptr_t)plat->regs; + int ret; + + ret = bitmask_from_clk_id(clk); + if (ret) + return ret; + + clrbits_le32(base_addr + plat->pllgrp, plat->bitmask); + return 0; } @@ -672,6 +789,7 @@ static int socfpga_clk_of_to_plat(struct udevice *dev) static struct clk_ops socfpga_clk_ops = { .enable = socfpga_clk_enable, + .disable = socfpga_clk_disable, .get_rate = socfpga_clk_get_rate, }; diff --git a/drivers/clk/altera/clk-agilex.h b/drivers/clk/altera/clk-agilex.h index b3e8841a512..be639957940 100644 --- a/drivers/clk/altera/clk-agilex.h +++ b/drivers/clk/altera/clk-agilex.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2019 Intel Corporation <www.intel.com> + * Copyright (C) 2025 Altera Corporation <www.altera.com> */ #ifndef _CLK_AGILEX_ @@ -210,7 +211,26 @@ struct cm_config { #define CLKMGR_LOSTLOCK_SET_MASK BIT(0) +#define CLKMGR_MAINPLLGRP_EN_MPUCLK_MASK BIT(0) +#define CLKMGR_MAINPLLGRP_EN_L4MAINCLK_MASK BIT(1) +#define CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK BIT(2) +#define CLKMGR_MAINPLLGRP_EN_L4SPCLK_MASK BIT(3) +#define CLKMGR_MAINPLLGRP_EN_CSCLK_MASK BIT(4) +#define CLKMGR_MAINPLLGRP_EN_CSTIMERCLK_MASK BIT(5) +#define CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK BIT(6) + +#define CLKMGR_PERPLLGRP_EN_EMAC0CLK_MASK BIT(0) +#define CLKMGR_PERPLLGRP_EN_EMAC1CLK_MASK BIT(1) +#define CLKMGR_PERPLLGRP_EN_EMAC2CLK_MASK BIT(2) +#define CLKMGR_PERPLLGRP_EN_EMACPTPCLK_MASK BIT(3) +#define CLKMGR_PERPLLGRP_EN_GPIODBCLK_MASK BIT(4) #define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK BIT(5) +#define CLKMGR_PERPLLGRP_EN_S2FUSER1CLK_MASK BIT(6) +#define CLKMGR_PERPLLGRP_EN_PSIREFCLK_MASK BIT(7) +#define CLKMGR_PERPLLGRP_EN_USBCLK_MASK BIT(8) +#define CLKMGR_PERPLLGRP_EN_SPIMCLK_MASK BIT(9) +#define CLKMGR_PERPLLGRP_EN_NANDCLK_MASK BIT(10) + #define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET 26 #define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK BIT(26) #define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET 27 diff --git a/drivers/clk/clk-cdce9xx.c b/drivers/clk/clk-cdce9xx.c index e5f74e714d5..996cc30683e 100644 --- a/drivers/clk/clk-cdce9xx.c +++ b/drivers/clk/clk-cdce9xx.c @@ -116,8 +116,7 @@ static int cdce9xx_clk_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &clk); data->xtal_rate = clk_get_rate(&clk); - val = dev_read_u32_default(dev, "xtal-load-pf", -1); - if (val >= 0) + if (!dev_read_u32(dev, "xtal-load-pf", &val)) cdce9xx_reg_write(dev, CDCE9XX_REG_XCSEL, val << 3); return 0; diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 7262e89b512..3dbe1ce9441 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -358,7 +358,7 @@ static int clk_set_default_rates(struct udevice *dev, ret = clk_set_rate(c, rates[index]); - if (ret < 0) { + if (IS_ERR_VALUE(ret)) { dev_warn(dev, "failed to set rate on clock index %d (%ld) (error = %d)\n", index, clk.id, ret); diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index 0c9a81cabcc..a7d89f32cd7 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -7,6 +7,7 @@ #include <clk-uclass.h> #include <dm.h> +#include <dm/device_compat.h> #include <scmi_agent.h> #include <scmi_agent-uclass.h> #include <scmi_protocols.h> @@ -41,19 +42,21 @@ static int scmi_clk_get_permissions(struct udevice *dev, int clkid, u32 *perm) }; if (priv->version < CLOCK_PROTOCOL_VERSION_3_0) { - log_debug("%s: SCMI clock management protocol version is less than 3.0.\n", __func__); + dev_dbg(dev, + "%s: SCMI clock management protocol version is less than 3.0.\n", __func__); return -EINVAL; } ret = devm_scmi_process_msg(dev, &msg); if (ret) { - log_debug("%s: get SCMI clock management protocol permissions failed\n", __func__); + dev_dbg(dev, + "%s: get SCMI clock management protocol permissions failed\n", __func__); return ret; } ret = scmi_to_linux_errno(out.status); if (ret < 0) { - log_debug("%s: the status code of getting permissions: %d\n", __func__, ret); + dev_dbg(dev, "%s: the status code of getting permissions: %d\n", __func__, ret); return ret; } @@ -167,7 +170,7 @@ static int scmi_clk_enable(struct clk *clk) return scmi_clk_gate(clk, 1); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ - log_debug("%s: SCMI CLOCK: the clock cannot be enabled by the agent.\n", __func__); + dev_dbg(clk->dev, "%s: SCMI CLOCK: the clock cannot be enabled by the agent.\n", __func__); return 0; } @@ -190,7 +193,8 @@ static int scmi_clk_disable(struct clk *clk) return scmi_clk_gate(clk, 0); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ - log_debug("%s: SCMI CLOCK: the clock cannot be disabled by the agent.\n", __func__); + dev_dbg(clk->dev, + "%s: SCMI CLOCK: the clock cannot be disabled by the agent.\n", __func__); return 0; } @@ -260,7 +264,8 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) return __scmi_clk_set_rate(clk, rate); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ - log_debug("%s: SCMI CLOCK: the clock rate cannot be changed by the agent.\n", __func__); + dev_dbg(clk->dev, + "%s: SCMI CLOCK: the clock rate cannot be changed by the agent.\n", __func__); return 0; } @@ -291,7 +296,7 @@ static int scmi_clk_probe(struct udevice *dev) ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_CLOCK, &priv->version); if (ret) { - log_debug("%s: get SCMI clock management protocol version failed\n", __func__); + dev_dbg(dev, "%s: get SCMI clock management protocol version failed\n", __func__); return ret; } @@ -371,7 +376,8 @@ static int scmi_clk_set_parent(struct clk *clk, struct clk *parent) return __scmi_clk_set_parent(clk, parent); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ - log_debug("%s: SCMI CLOCK: the clock's parent cannot be changed by the agent.\n", __func__); + dev_dbg(clk->dev, + "%s: SCMI CLOCK: the clock's parent cannot be changed by the agent.\n", __func__); return 0; } diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c index 4f67c958d0f..7a433a667a4 100644 --- a/drivers/clk/clk_zynqmp.c +++ b/drivers/clk/clk_zynqmp.c @@ -882,7 +882,7 @@ static int zynqmp_clk_enable(struct clk *clk) return ret; } -static struct clk_ops zynqmp_clk_ops = { +static const struct clk_ops zynqmp_clk_ops = { .set_rate = zynqmp_clk_set_rate, .get_rate = zynqmp_clk_get_rate, .enable = zynqmp_clk_enable, diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 74d5fe73f94..644ab162af4 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -167,3 +167,12 @@ config CLK_IMXRT1170 select CLK_CCF help This enables support clock driver for i.MXRT1170 platforms. + +config CLK_IMX95_BLKCTRL + bool "Enable i.MX95 blkctrl clock driver" + depends on IMX95 || IMX94 + select CLK + select CLK_CCF + select CLK_AUTO_ID + help + Enable support for clocks in i.MX95 MIX blkctrl like HSIO and LVDS. diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b10221a195c..f2fd6ff8ca0 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_$(PHASE_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o \ obj-$(CONFIG_$(PHASE_)CLK_IMXRT1020) += clk-imxrt1020.o obj-$(CONFIG_$(PHASE_)CLK_IMXRT1050) += clk-imxrt1050.o obj-$(CONFIG_$(PHASE_)CLK_IMXRT1170) += clk-imxrt1170.o +obj-$(CONFIG_CLK_IMX95_BLKCTRL) += clk-imx95-blkctrl.o diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 13239f2f64d..b69355cefc7 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -156,6 +156,12 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_gate2(dev, "i2c3", "ipg_per", base + 0x70, 10)); clk_dm(IMX6QDL_CLK_PWM1, imx_clk_gate2(dev, "pwm1", "ipg_per", base + 0x78, 16)); + clk_dm(IMX6QDL_CLK_PWM2, + imx_clk_gate2(dev, "pwm2", "ipg_per", base + 0x78, 18)); + clk_dm(IMX6QDL_CLK_PWM3, + imx_clk_gate2(dev, "pwm3", "ipg_per", base + 0x78, 20)); + clk_dm(IMX6QDL_CLK_PWM4, + imx_clk_gate2(dev, "pwm4", "ipg_per", base + 0x78, 22)); clk_dm(IMX6QDL_CLK_ENET, imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10)); clk_dm(IMX6QDL_CLK_ENET_REF, diff --git a/drivers/clk/imx/clk-imx95-blkctrl.c b/drivers/clk/imx/clk-imx95-blkctrl.c new file mode 100644 index 00000000000..3e6f53b4a16 --- /dev/null +++ b/drivers/clk/imx/clk-imx95-blkctrl.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2023-2025 NXP + * + */ + +#include <asm/io.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dt-bindings/clock/nxp,imx95-clock.h> +#include <linux/clk-provider.h> + +#include "clk.h" + +enum { + CLK_GATE, + CLK_DIVIDER, + CLK_MUX, +}; + +struct imx95_blk_ctl_clk_dev_data { + const char *name; + const char * const *parent_names; + u32 num_parents; + u32 reg; + u32 bit_idx; + u32 clk_type; + u32 flags; + u32 flags2; + u32 type; +}; + +struct imx95_blk_ctl_dev_data { + const struct imx95_blk_ctl_clk_dev_data *clk_dev_data; + u32 num_clks; + u32 clk_reg_offset; +}; + +static const struct imx95_blk_ctl_clk_dev_data hsio_blk_ctl_clk_dev_data[] = { + [0] = { + .name = "hsio_blk_ctl_clk", + .parent_names = (const char *[]){ "hsiopll", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 6, + .type = CLK_GATE, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static const struct imx95_blk_ctl_dev_data hsio_blk_ctl_dev_data = { + .num_clks = 1, + .clk_dev_data = hsio_blk_ctl_clk_dev_data, + .clk_reg_offset = 0, +}; + +static const struct imx95_blk_ctl_clk_dev_data imx95_lvds_clk_dev_data[] = { + [IMX95_CLK_DISPMIX_LVDS_PHY_DIV] = { + .name = "ldb_phy_div", + .parent_names = (const char *[]){ "ldbpll", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 0, + .type = CLK_DIVIDER, + .flags2 = CLK_DIVIDER_POWER_OF_TWO, + }, + + [IMX95_CLK_DISPMIX_LVDS_CH0_GATE] = { + .name = "lvds_ch0_gate", + .parent_names = (const char *[]){ "ldb_phy_div", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 1, + .type = CLK_GATE, + .flags = CLK_SET_RATE_PARENT, + .flags2 = CLK_GATE_SET_TO_DISABLE, + }, + [IMX95_CLK_DISPMIX_LVDS_CH1_GATE] = { + .name = "lvds_ch1_gate", + .parent_names = (const char *[]){ "ldb_phy_div", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 2, + .type = CLK_GATE, + .flags = CLK_SET_RATE_PARENT, + .flags2 = CLK_GATE_SET_TO_DISABLE, + }, + [IMX95_CLK_DISPMIX_PIX_DI0_GATE] = { + .name = "lvds_di0_gate", + .parent_names = (const char *[]){ "ldb_pll_div7", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 3, + .type = CLK_GATE, + .flags = CLK_SET_RATE_PARENT, + .flags2 = CLK_GATE_SET_TO_DISABLE, + }, + [IMX95_CLK_DISPMIX_PIX_DI1_GATE] = { + .name = "lvds_di1_gate", + .parent_names = (const char *[]){ "ldb_pll_div7", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 4, + .type = CLK_GATE, + .flags = CLK_SET_RATE_PARENT, + .flags2 = CLK_GATE_SET_TO_DISABLE, + }, +}; + +static const struct imx95_blk_ctl_dev_data imx95_lvds_csr_dev_data = { + .num_clks = ARRAY_SIZE(imx95_lvds_clk_dev_data), + .clk_dev_data = imx95_lvds_clk_dev_data, + .clk_reg_offset = 0, +}; + +static int imx95_blkctrl_clk_probe(struct udevice *dev) +{ + int i; + void __iomem *addr; + struct imx95_blk_ctl_dev_data *dev_data = (void *)dev_get_driver_data(dev); + const struct imx95_blk_ctl_clk_dev_data *clk_dev_data; + + addr = dev_read_addr_ptr(dev); + if (addr == (void *)FDT_ADDR_T_NONE) { + dev_err(dev, "No blkctrl register base address\n"); + return -EINVAL; + } + + if (!dev_data) { + dev_err(dev, "driver data is NULL\n"); + return -EINVAL; + } + + clk_dev_data = dev_data->clk_dev_data; + for (i = 0; i < dev_data->num_clks; i++) { + if (clk_dev_data[i].clk_type == CLK_GATE) { + dev_clk_dm(dev, i, + clk_register_gate(dev, + clk_dev_data[i].name, + clk_dev_data[i].parent_names[0], + clk_dev_data[i].flags, addr + + dev_data->clk_reg_offset, + clk_dev_data[i].bit_idx, + clk_dev_data[i].flags2, NULL)); + } else if (clk_dev_data[i].clk_type == CLK_DIVIDER) { + dev_clk_dm(dev, i, + clk_register_divider(dev, clk_dev_data[i].name, + clk_dev_data[i].parent_names[0], + clk_dev_data[i].flags, addr + + dev_data->clk_reg_offset, + clk_dev_data[i].bit_idx, 1, + clk_dev_data[i].flags2)); + } else if (clk_dev_data[i].clk_type == CLK_MUX) { + dev_clk_dm(dev, i, + clk_register_mux(dev, + clk_dev_data[i].name, + clk_dev_data[i].parent_names, + clk_dev_data[i].num_parents, + clk_dev_data[i].flags, addr + + dev_data->clk_reg_offset, + clk_dev_data[i].bit_idx, 1, + clk_dev_data[i].flags2)); + } + } + + return 0; +} + +static const struct udevice_id imx95_blkctrl_clk_ids[] = { + { .compatible = "nxp,imx95-lvds-csr", .data = (ulong)&imx95_lvds_csr_dev_data, }, + { .compatible = "nxp,imx95-hsio-blk-ctl", .data = (ulong)&hsio_blk_ctl_dev_data, }, + { }, +}; + +U_BOOT_DRIVER(imx95_blkctrl_clk) = { + .name = "imx95_blkctrl_clk", + .id = UCLASS_CLK, + .of_match = imx95_blkctrl_clk_ids, + .ops = &ccf_clk_ops, + .probe = imx95_blkctrl_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 5d7faaa3eab..a7a42b2edb6 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -916,8 +916,6 @@ static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, return -EINVAL; case CLKID_PCIE_PLL: return meson_pcie_pll_set_rate(clk, rate); - - return 0; case CLKID_VPU: return meson_clk_set_rate_by_id(clk, meson_mux_get_parent(clk, CLKID_VPU), rate, diff --git a/drivers/clk/stm32/clk-stm32mp25.c b/drivers/clk/stm32/clk-stm32mp25.c index 18c0b1cb867..b487f33b6c7 100644 --- a/drivers/clk/stm32/clk-stm32mp25.c +++ b/drivers/clk/stm32/clk-stm32mp25.c @@ -430,7 +430,7 @@ static int stm32mp25_check_security(struct udevice *dev, void __iomem *base, u32 index = (u32)cfg->sec_id; if (index & SEC_RIFSC_FLAG) - ret = stm32_rifsc_check_access_by_id(dev_ofnode(dev), + ret = stm32_rifsc_grant_access_by_id(dev_ofnode(dev), index & ~SEC_RIFSC_FLAG); else ret = stm32_rcc_get_access(dev, index); diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 822cf0809d5..6899e1b595a 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -235,6 +235,7 @@ U_BOOT_DRIVER(th1520_clk_div) = { .name = "th1520_clk_div", .id = UCLASS_CLK, .ops = &ccu_div_ops, + .flags = DM_FLAG_PRE_RELOC, }; static unsigned long th1520_pll_vco_recalc_rate(struct clk *clk, @@ -302,6 +303,7 @@ U_BOOT_DRIVER(th1520_clk_pll) = { .name = "th1520_clk_pll", .id = UCLASS_CLK, .ops = &clk_pll_ops, + .flags = DM_FLAG_PRE_RELOC, }; static struct ccu_pll cpu_pll0_clk = { @@ -1030,4 +1032,5 @@ U_BOOT_DRIVER(th1520_clk) = { .of_match = th1520_clk_match, .probe = th1520_clk_probe, .ops = &th1520_clk_ops, + .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/core/root.c b/drivers/core/root.c index e53381e3b32..d43645f34dd 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -32,7 +32,7 @@ DECLARE_GLOBAL_DATA_PTR; -static struct driver_info root_info = { +static const struct driver_info root_info = { .name = "root_driver", }; diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c index 950630453f9..5f17122c36c 100644 --- a/drivers/cpu/imx8_cpu.c +++ b/drivers/cpu/imx8_cpu.c @@ -113,6 +113,8 @@ static const char *get_imx_type_str(u32 imxtype) return "91(01)";/* iMX91 9x9 Specific feature */ case MXC_CPU_IMX95: return "95"; + case MXC_CPU_IMX94: + return "94"; default: return "??"; } @@ -190,7 +192,7 @@ static int cpu_imx_get_temp(struct cpu_imx_plat *plat) return 0xdeadbeef; } - return cpu_tmp; + return cpu_tmp / 1000; } #else static int cpu_imx_get_temp(struct cpu_imx_plat *plat) diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index 8f7a821ebf3..07d336c074a 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -642,7 +642,7 @@ static int rng_init(uint8_t sec_idx, ccsr_sec_t *sec) */ if (!inst_handles) { kick_trng(ent_delay, sec); - ent_delay += 400; + ent_delay = ent_delay * 2; } /* * if instantiate_rng(...) fails, the loop will rerun diff --git a/drivers/crypto/fsl/rng.c b/drivers/crypto/fsl/rng.c index 786a710f5fb..06f37a8b4de 100644 --- a/drivers/crypto/fsl/rng.c +++ b/drivers/crypto/fsl/rng.c @@ -23,11 +23,26 @@ struct caam_rng_priv { u8 data[CAAM_RNG_MAX_FIFO_STORE_SIZE] __aligned(ARCH_DMA_MINALIGN); }; +static int caam_init_desc(struct caam_rng_priv *priv) +{ + ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN); + + inline_cnstr_jobdesc_rng(priv->desc, priv->data, + CAAM_RNG_MAX_FIFO_STORE_SIZE); + + flush_dcache_range((unsigned long)priv->desc, + (unsigned long)priv->desc + size); + + return 0; +} + static int caam_rng_read_one(struct caam_rng_priv *priv) { int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN); int ret; + caam_init_desc(priv); + ret = run_descriptor_jr(priv->desc); if (ret < 0) return -EIO; @@ -63,12 +78,8 @@ static int caam_rng_read(struct udevice *dev, void *data, size_t len) static int caam_rng_probe(struct udevice *dev) { struct caam_rng_priv *priv = dev_get_priv(dev); - ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN); - inline_cnstr_jobdesc_rng(priv->desc, priv->data, - CAAM_RNG_MAX_FIFO_STORE_SIZE); - flush_dcache_range((unsigned long)priv->desc, - (unsigned long)priv->desc + size); + caam_init_desc(priv); return 0; } diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c index 21f94959a04..2a2f86a650e 100644 --- a/drivers/ddr/altera/iossm_mailbox.c +++ b/drivers/ddr/altera/iossm_mailbox.c @@ -38,6 +38,8 @@ #define IOSSM_STATUS_CMD_RESPONSE_ERROR(n) FIELD_GET(IOSSM_STATUS_CMD_RESPONSE_ERROR_MASK, n) #define IOSSM_STATUS_GENERAL_ERROR_MASK GENMASK(4, 1) #define IOSSM_STATUS_GENERAL_ERROR(n) FIELD_GET(IOSSM_STATUS_GENERAL_ERROR_MASK, n) +#define IOSSM_MAILBOX_SPEC_VERSION_MASK GENMASK(2, 0) +#define IOSSM_MAILBOX_SPEC_VERSION(n) FIELD_GET(IOSSM_MAILBOX_SPEC_VERSION_MASK, n) /* Offset of Mailbox Read-only Registers */ #define IOSSM_MAILBOX_HEADER_OFFSET 0x0 @@ -383,6 +385,23 @@ err: return ret; } +static bool is_mailbox_spec_compatible(struct io96b_info *io96b_ctrl) +{ + u32 mailbox_header; + u8 mailbox_spec_ver; + + mailbox_header = readl(io96b_ctrl->io96b[0].io96b_csr_addr + + IOSSM_MAILBOX_HEADER_OFFSET); + mailbox_spec_ver = IOSSM_MAILBOX_SPEC_VERSION(mailbox_header); + printf("%s: IOSSM mailbox version: %d\n", __func__, mailbox_spec_ver); + + /* for now there are two mailbox spec versions, 0 and 1; only version 1 is compatible */ + if (!mailbox_spec_ver) + return false; + + return true; +} + /* * Initial function to be called to set memory interface IP type and instance ID * IP type and instance ID need to be determined before sending mailbox command @@ -392,6 +411,11 @@ void io96b_mb_init(struct io96b_info *io96b_ctrl) int i, j; u32 mem_intf_info_0, mem_intf_info_1; + if (!is_mailbox_spec_compatible(io96b_ctrl)) { + printf("DDR: Failed to get compatible mailbox version\n"); + hang(); + } + debug("%s: num_instance %d\n", __func__, io96b_ctrl->num_instance); for (i = 0; i < io96b_ctrl->num_instance; i++) { diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c index f8fc92060db..2d0093c591c 100644 --- a/drivers/ddr/altera/sdram_soc64.c +++ b/drivers/ddr/altera/sdram_soc64.c @@ -85,11 +85,11 @@ int emif_reset(struct altera_sdram_plat *plat) debug("DDR: Triggerring emif reset\n"); hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL); - /* if seq2core[3] = 0, we are good */ + /* if seq2core[2:0] = 0b0000_0111, we are good */ ret = wait_for_bit_le32((const void *)(plat->hmc + RSTHANDSHAKESTAT), - DDR_HMC_SEQ2CORE_INT_RESP_MASK, - false, 1000, false); + DDR_HMC_SEQ2CORE_INT_REQ_ACK_MASK, + true, 1000, false); if (ret) { printf("DDR: failed to get ack from EMIF\n"); return ret; diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h index 6031cef560e..6fe0653922c 100644 --- a/drivers/ddr/altera/sdram_soc64.h +++ b/drivers/ddr/altera/sdram_soc64.h @@ -77,7 +77,7 @@ struct altera_sdram_plat { #define DDR_HMC_INTMODE_INTMODE_SET_MSK BIT(0) #define DDR_HMC_RSTHANDSHAKE_MASK 0x0000000f #define DDR_HMC_CORE2SEQ_INT_REQ 0x0000000f -#define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3) +#define DDR_HMC_SEQ2CORE_INT_REQ_ACK_MASK GENMASK(2, 0) #define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f #define DDR_HMC_ERRINTEN_INTMASK \ diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index 9a25192c079..fea08c9000f 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -2173,7 +2173,7 @@ static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en) /* Normal Operation Short Calibration Time (tZQCS) */ unsigned int zqcs = 0; #ifdef CONFIG_SYS_FSL_DDR4 - unsigned int zqcs_init; + unsigned int zqcs_init = 0; #endif if (zq_en) { diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index e33b0056d0b..2cf4289b448 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -98,6 +98,7 @@ config DFU_SCSI config SET_DFU_ALT_INFO bool "Dynamic set of DFU alternate information" + depends on !COMPILE_TEST help This option allows to call the function set_dfu_alt_info to dynamically build dfu_alt_info in board. diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index afc64fd5280..6df3917e129 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -157,8 +157,13 @@ int fastboot_nand_get_part_info(const char *part_name, struct part_info **part_info, char *response) { struct mtd_info *mtd = NULL; + int ret; + + ret = fb_nand_lookup(part_name, &mtd, part_info, response); + if (ret) + return -ENOENT; - return fb_nand_lookup(part_name, &mtd, part_info, response); + return ret; } /** diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c index 6d4497f4b92..16a82f55ab7 100644 --- a/drivers/firmware/scmi/mailbox_agent.c +++ b/drivers/firmware/scmi/mailbox_agent.c @@ -16,7 +16,7 @@ #include "smt.h" -#define TIMEOUT_US_10MS 10000 +#define TIMEOUT_30MS 30 /** * struct scmi_mbox_channel - Description of an SCMI mailbox transport @@ -73,6 +73,7 @@ out: static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan) { + struct scmi_mbox_channel *base_chan = dev_get_plat(dev); int ret; ret = mbox_get_by_index(dev, 0, &chan->mbox); @@ -87,7 +88,7 @@ static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan) return ret; } - chan->timeout_us = TIMEOUT_US_10MS; + chan->timeout_us = base_chan->timeout_us; return 0; } @@ -127,6 +128,9 @@ int scmi_mbox_of_to_plat(struct udevice *dev) { struct scmi_mbox_channel *chan = dev_get_plat(dev); + chan->timeout_us = dev_read_u32_default(dev, "arm,max-rx-timeout-ms", + TIMEOUT_30MS) * 1000; + return setup_channel(dev, chan); } diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index e7ec2c108e6..69a277e8786 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -35,6 +35,7 @@ static const struct error_code scmi_linux_errmap[] = { { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, }, { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, }, { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, }, + { .scmi = SCMI_IN_USE, .errno = -EADDRINUSE, }, }; /** diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c index 3253f4211d6..237871559f0 100644 --- a/drivers/firmware/scmi/smt.c +++ b/drivers/firmware/scmi/smt.c @@ -25,9 +25,9 @@ static void scmi_smt_enable_intr(struct scmi_smt *smt, bool enable) struct scmi_smt_header *hdr = (void *)smt->buf; if (enable) - hdr->flags |= SCMI_SHMEM_FLAG_INTR_ENABLED; + iowrite32(ioread32(&hdr->flags) | SCMI_SHMEM_FLAG_INTR_ENABLED, &hdr->flags); else - hdr->flags &= ~SCMI_SHMEM_FLAG_INTR_ENABLED; + iowrite32(ioread32(&hdr->flags) & ~SCMI_SHMEM_FLAG_INTR_ENABLED, &hdr->flags); } /** @@ -62,11 +62,17 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt) scmi_smt_enable_intr(smt, true); #ifdef CONFIG_ARM - if (dcache_status()) - mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, MMU_SECTION_SIZE), - ALIGN(smt->size, MMU_SECTION_SIZE), - DCACHE_OFF); + if (dcache_status()) { + u32 align_size; + if (IS_ENABLED(CONFIG_ARM64)) + align_size = PAGE_SIZE; + else + align_size = MMU_SECTION_SIZE; + + mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, align_size), + ALIGN(smt->size, align_size), DCACHE_OFF); + } #endif return 0; @@ -85,24 +91,27 @@ int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt, (!msg->out_msg && msg->out_msg_sz)) return -EINVAL; - if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) { + if (!(ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) { dev_dbg(dev, "Channel busy\n"); return -EBUSY; } if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) || smt->size < (sizeof(*hdr) + msg->out_msg_sz)) { - dev_dbg(dev, "Buffer too small\n"); + dev_err(dev, + "Buffer write too small: mst->size:%zu, in_msg_sz:%zu, out_msg_sz:%zu\n", + smt->size, msg->in_msg_sz, msg->out_msg_sz); return -ETOOSMALL; } /* Load message in shared memory */ - hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE; - hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header); - hdr->msg_header = SMT_HEADER_TOKEN(0) | - SMT_HEADER_MESSAGE_TYPE(0) | - SMT_HEADER_PROTOCOL_ID(msg->protocol_id) | - SMT_HEADER_MESSAGE_ID(msg->message_id); + iowrite32(ioread32(&hdr->channel_status) & ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, + &hdr->channel_status); + iowrite32(msg->in_msg_sz + sizeof(hdr->msg_header), &hdr->length); + iowrite32(SMT_HEADER_TOKEN(0) | + SMT_HEADER_MESSAGE_TYPE(0) | + SMT_HEADER_PROTOCOL_ID(msg->protocol_id) | + SMT_HEADER_MESSAGE_ID(msg->message_id), &hdr->msg_header); memcpy_toio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz); @@ -118,23 +127,24 @@ int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt, { struct scmi_smt_header *hdr = (void *)smt->buf; - if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) { + if (!(ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) { dev_err(dev, "Channel unexpectedly busy\n"); return -EBUSY; } - if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) { + if (ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) { dev_err(dev, "Channel error reported, reset channel\n"); return -ECOMM; } - if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) { - dev_err(dev, "Buffer to small\n"); + if (ioread32(&hdr->length) > msg->out_msg_sz + sizeof(hdr->msg_header)) { + dev_err(dev, "Buffer too small: hdr->length:%u, out_msg_sz:%zu\n", + ioread32(&hdr->length), msg->out_msg_sz); return -ETOOSMALL; } /* Get the data */ - msg->out_msg_sz = hdr->length - sizeof(hdr->msg_header); + msg->out_msg_sz = ioread32(&hdr->length) - sizeof(hdr->msg_header); memcpy_fromio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz); return 0; @@ -147,7 +157,8 @@ void scmi_clear_smt_channel(struct scmi_smt *smt) { struct scmi_smt_header *hdr = (void *)smt->buf; - hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR; + iowrite32(ioread32(&hdr->channel_status) & ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR, + &hdr->channel_status); } /** @@ -165,18 +176,19 @@ int scmi_msg_to_smt_msg(struct udevice *dev, struct scmi_smt *smt, if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) || smt->size < (sizeof(*hdr) + msg->out_msg_sz)) { - dev_dbg(dev, "Buffer too small\n"); + dev_err(dev, "Buffer too small: mst->size:%zu, in_msg_sz:%zu, out_msg_sz:%zu\n", + smt->size, msg->in_msg_sz, msg->out_msg_sz); return -ETOOSMALL; } *buf_size = msg->in_msg_sz + sizeof(hdr->msg_header); - hdr->msg_header = SMT_HEADER_TOKEN(0) | - SMT_HEADER_MESSAGE_TYPE(0) | - SMT_HEADER_PROTOCOL_ID(msg->protocol_id) | - SMT_HEADER_MESSAGE_ID(msg->message_id); + iowrite32(SMT_HEADER_TOKEN(0) | + SMT_HEADER_MESSAGE_TYPE(0) | + SMT_HEADER_PROTOCOL_ID(msg->protocol_id) | + SMT_HEADER_MESSAGE_ID(msg->message_id), &hdr->msg_header); - memcpy(hdr->msg_payload, msg->in_msg, msg->in_msg_sz); + memcpy_fromio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz); return 0; } @@ -191,12 +203,13 @@ int scmi_msg_from_smt_msg(struct udevice *dev, struct scmi_smt *smt, struct scmi_smt_msg_header *hdr = (void *)smt->buf; if (buf_size > msg->out_msg_sz + sizeof(hdr->msg_header)) { - dev_err(dev, "Buffer to small\n"); + dev_err(dev, "Buffer too small: buf_size:%zu, out_msg_sz:%zu\n", + buf_size, msg->out_msg_sz); return -ETOOSMALL; } msg->out_msg_sz = buf_size - sizeof(hdr->msg_header); - memcpy(msg->out_msg, hdr->msg_payload, msg->out_msg_sz); + memcpy_toio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz); return 0; } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 58e464106a3..db077e472a8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -695,12 +695,6 @@ config SLG7XL45106_I2C_GPO 8-bit gpo expander, all gpo lines are controlled by writing value into data register. -config FTGPIO010 - bool "Faraday Technology FTGPIO010 driver" - depends on DM_GPIO - help - Support for GPIOs on Faraday Technology's FTGPIO010 controller. - config ADP5585_GPIO bool "ADP5585 GPIO driver" depends on DM_GPIO && DM_I2C diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 83e10c79b91..73c94329e36 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -77,7 +77,6 @@ obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o obj-$(CONFIG_ADP5588_GPIO) += adp5588_gpio.o obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o -obj-$(CONFIG_FTGPIO010) += ftgpio010.o obj-$(CONFIG_$(PHASE_)ADP5585_GPIO) += adp5585_gpio.o obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o obj-$(CONFIG_MPFS_GPIO) += mpfs_gpio.o diff --git a/drivers/gpio/adp5588_gpio.c b/drivers/gpio/adp5588_gpio.c index d081e169897..36304e48893 100644 --- a/drivers/gpio/adp5588_gpio.c +++ b/drivers/gpio/adp5588_gpio.c @@ -168,7 +168,7 @@ static int adp5588_ofdata_platdata(struct udevice *dev) revid = ret & ID_MASK; - printf("ADP5588 Detected: Rev %x, Rev ID %x\n", ret, revid); + printf("ADP558x Detected: Rev %x, Rev ID %x\n", ret, revid); for (i = 0, ret = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) { plat->dat_out[i] = adp5588_gpio_read(dev, GPIO_DAT_OUT1 + i); @@ -194,6 +194,7 @@ static const struct dm_gpio_ops adp5588_ops = { static const struct udevice_id adp5588_of_match_list[] = { { .compatible = "adi,adp5588"}, + { .compatible = "adi,adp5587"}, { /* sentinel */ } }; diff --git a/drivers/gpio/dwapb_gpio.c b/drivers/gpio/dwapb_gpio.c index 04639a4cb68..7ab48780332 100644 --- a/drivers/gpio/dwapb_gpio.c +++ b/drivers/gpio/dwapb_gpio.c @@ -193,7 +193,7 @@ static int gpio_dwapb_bind(struct udevice *dev) ofnode_get_name(node)); plat->name = strdup(name); if (!plat->name) { - kfree(plat); + devm_kfree(dev, plat); return -ENOMEM; } } diff --git a/drivers/gpio/ftgpio010.c b/drivers/gpio/ftgpio010.c deleted file mode 100644 index 4cb550a540c..00000000000 --- a/drivers/gpio/ftgpio010.c +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Faraday Technology's FTGPIO010 controller. - */ - -#include <dm.h> -#include <asm/io.h> -#include <asm/gpio.h> - -struct ftgpio010_regs { - u32 out; - u32 in; - u32 direction; // 1 - output - u32 reserved; - u32 set; - u32 clear; -}; - -struct ftgpio010_plat { - struct ftgpio010_regs __iomem *regs; -}; - -static int ftgpio010_direction_input(struct udevice *dev, unsigned int pin) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - clrbits_le32(®s->direction, 1 << pin); - return 0; -} - -static int ftgpio010_direction_output(struct udevice *dev, unsigned int pin, - int val) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - /* change the data first, then the direction. to avoid glitch */ - out_le32(val ? ®s->set : ®s->clear, 1 << pin); - setbits_le32(®s->direction, 1 << pin); - - return 0; -} - -static int ftgpio010_get_value(struct udevice *dev, unsigned int pin) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - return in_le32(®s->in) >> pin & 1; -} - -static int ftgpio010_set_value(struct udevice *dev, unsigned int pin, int val) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - out_le32(val ? ®s->set : ®s->clear, 1 << pin); - return 0; -} - -static int ftgpio010_get_function(struct udevice *dev, unsigned int pin) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - if (in_le32(®s->direction) >> pin & 1) - return GPIOF_OUTPUT; - return GPIOF_INPUT; -} - -static int ftgpio010_probe(struct udevice *dev) -{ - struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - - uc_priv->gpio_count = ofnode_read_u32_default(dev_ofnode(dev), - "nr-gpios", 32); - return 0; -} - -static int ftgpio010_of_to_plat(struct udevice *dev) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - - plat->regs = dev_read_addr_ptr(dev); - return 0; -} - -static const struct dm_gpio_ops ftgpio010_ops = { - .direction_input = ftgpio010_direction_input, - .direction_output = ftgpio010_direction_output, - .get_value = ftgpio010_get_value, - .set_value = ftgpio010_set_value, - .get_function = ftgpio010_get_function, -}; - -static const struct udevice_id ftgpio010_ids[] = { - { .compatible = "faraday,ftgpio010" }, - { } -}; - -U_BOOT_DRIVER(ftgpio010) = { - .name = "ftgpio010", - .id = UCLASS_GPIO, - .of_match = ftgpio010_ids, - .ops = &ftgpio010_ops, - .of_to_plat = ftgpio010_of_to_plat, - .plat_auto = sizeof(struct ftgpio010_plat), - .probe = ftgpio010_probe, -}; diff --git a/drivers/gpio/gpio-aspeed-g7.c b/drivers/gpio/gpio-aspeed-g7.c index 4c6ab86203c..4607468ca05 100644 --- a/drivers/gpio/gpio-aspeed-g7.c +++ b/drivers/gpio/gpio-aspeed-g7.c @@ -141,7 +141,7 @@ static const struct udevice_id aspeed_gpio_ids[] = { { } }; -U_BOOT_DRIVER(gpio_aspeed) = { +U_BOOT_DRIVER(gpio_aspeed_g7) = { .name = "gpio-aspeed", .id = UCLASS_GPIO, .of_match = aspeed_gpio_ids, diff --git a/drivers/gpio/mpfs_gpio.c b/drivers/gpio/mpfs_gpio.c index 9bbeada4ef5..35eed596c10 100644 --- a/drivers/gpio/mpfs_gpio.c +++ b/drivers/gpio/mpfs_gpio.c @@ -75,7 +75,7 @@ static int mchp_gpio_direction_output(struct udevice *dev, u32 offset, int value return 0; } -static bool mchp_gpio_get_value(struct udevice *dev, u32 offset) +static int mchp_gpio_get_value(struct udevice *dev, u32 offset) { struct mchp_gpio_plat *plat = dev_get_plat(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); @@ -136,7 +136,7 @@ static int mchp_gpio_probe(struct udevice *dev) struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); char name[18], *str; - plat->regs = dev_get_driver_data(dev); + plat->regs = (struct mpfs_gpio_reg_offsets *)dev_get_driver_data(dev); sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base); str = strdup(name); if (!str) @@ -160,10 +160,10 @@ static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets = { static const struct udevice_id mchp_gpio_match[] = { { .compatible = "microchip,mpfs-gpio", - .data = &mpfs_reg_offsets, + .data = (unsigned long)&mpfs_reg_offsets, }, { .compatible = "microchip,coregpio-rtl-v3", - .data = &coregpio_reg_offsets, + .data = (unsigned long)&coregpio_reg_offsets, }, { /* end of list */ } }; diff --git a/drivers/i2c/davinci_i2c.c b/drivers/i2c/davinci_i2c.c index 39132747208..9bba0600e3e 100644 --- a/drivers/i2c/davinci_i2c.c +++ b/drivers/i2c/davinci_i2c.c @@ -19,6 +19,7 @@ #include <asm/arch/i2c_defs.h> #include <asm/io.h> #include <linux/delay.h> +#include <linux/types.h> #include "davinci_i2c.h" /* Information about i2c controller */ @@ -87,7 +88,7 @@ static void _flush_rx(struct i2c_regs *i2c_base) static uint _davinci_i2c_setspeed(struct i2c_regs *i2c_base, uint speed) { - uint32_t div, psc; + u32 div, psc; psc = 2; /* SCLL + SCLH */ @@ -122,10 +123,10 @@ static void _davinci_i2c_init(struct i2c_regs *i2c_base, udelay(1000); } -static int _davinci_i2c_read(struct i2c_regs *i2c_base, uint8_t chip, - uint32_t addr, int alen, uint8_t *buf, int len) +static int _davinci_i2c_read(struct i2c_regs *i2c_base, u8 chip, + u32 addr, int alen, u8 *buf, int len) { - uint32_t tmp; + u32 tmp; int i; if ((alen < 0) || (alen > 2)) { @@ -220,10 +221,10 @@ static int _davinci_i2c_read(struct i2c_regs *i2c_base, uint8_t chip, return 0; } -static int _davinci_i2c_write(struct i2c_regs *i2c_base, uint8_t chip, - uint32_t addr, int alen, uint8_t *buf, int len) +static int _davinci_i2c_write(struct i2c_regs *i2c_base, u8 chip, + u32 addr, int alen, u8 *buf, int len) { - uint32_t tmp; + u32 tmp; int i; if ((alen < 0) || (alen > 2)) { @@ -302,7 +303,7 @@ static int _davinci_i2c_write(struct i2c_regs *i2c_base, uint8_t chip, return 0; } -static int _davinci_i2c_probe_chip(struct i2c_regs *i2c_base, uint8_t chip) +static int _davinci_i2c_probe_chip(struct i2c_regs *i2c_base, u8 chip) { int rc = 1; diff --git a/drivers/i2c/npcm_i2c.c b/drivers/i2c/npcm_i2c.c index c64752e1467..bff0d04f1a5 100644 --- a/drivers/i2c/npcm_i2c.c +++ b/drivers/i2c/npcm_i2c.c @@ -34,6 +34,7 @@ #define SMBCTL3_SDA_LVL BIT(6) /* SMBCST */ +#define SMBCST_BUSY BIT(0) #define SMBCST_BB BIT(1) #define SMBCST_TGSCL BIT(5) @@ -479,11 +480,17 @@ static int npcm_i2c_xfer(struct udevice *dev, struct npcm_i2c_bus *bus = dev_get_priv(dev); struct npcm_i2c_regs *reg = bus->reg; int ret = 0, err = 0; + u8 val; if (nmsgs < 1 || nmsgs > 2) { printf("%s: commands not support\n", __func__); return -EREMOTEIO; } + + /* Wait for module out of busy */ + if (readb_poll_timeout(®->cst, val, !(val & SMBCST_BUSY), 1000)) + return -EBUSY; + /* clear ST register */ writeb(0xFF, ®->st); diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index a6361d3d17d..2c6f8ea5901 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -134,12 +134,10 @@ static const u8 __maybe_unused reg_map_ip_v2[] = { }; struct omap_i2c { - struct udevice *clk; int ip_rev; struct i2c *regs; unsigned int speed; int waitdelay; - int clk_id; }; static inline const u8 *omap_i2c_get_ip_reg_map(int ip_rev) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index d96eb9b134e..0c4af7e528a 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -21,10 +21,6 @@ #include <linux/iopoll.h> #include <linux/i3c/master.h> -#ifdef CONFIG_SANDBOX -#define cpu_relax() do {} while (0) -#endif - static u8 even_parity(u8 p) { p ^= p >> 4; diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index c98cbf92fab..a37ec633fb6 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -137,7 +137,8 @@ config SPL_LED_GPIO See the help of LED_GPIO for details. config LED_STATUS - bool "Enable status LED API" + bool "Enable legacy status LED API" + depends on !LED help Allows common u-boot commands to use a board's leds to provide status for activities like booting and downloading files. diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c index f62277385fb..79266c56e79 100644 --- a/drivers/mailbox/zynqmp-ipi.c +++ b/drivers/mailbox/zynqmp-ipi.c @@ -241,7 +241,7 @@ static int zynqmp_ipi_probe(struct udevice *dev) return 0; }; -struct mbox_ops zynqmp_ipi_dest_mbox_ops = { +static const struct mbox_ops zynqmp_ipi_dest_mbox_ops = { .send = zynqmp_ipi_send, .recv = zynqmp_ipi_recv, }; diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 18238765ead..591d9d9c656 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -37,6 +37,23 @@ config STM32_FMC2_EBI devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on SOCs containing the FMC2 External Bus Interface. +config STM32_OMM + bool "STM32 Octo Memory Manager" + depends on ARCH_STM32MP + help + This driver manages the muxing between the 2 OSPI busses and + the 2 output ports. There are 4 possible muxing configurations: + - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2 + output is on port 2 + - OSPI1 and OSPI2 are multiplexed over the same output port 1 + - swapped mode (no multiplexing), OSPI1 output is on port 2, + OSPI2 output is on port 1 + - OSPI1 and OSPI2 are multiplexed over the same output port 2 + It also manages : + - the split of the memory area shared between the 2 OSPI instances. + - chip select selection override. + - the time between 2 transactions in multiplexed mode. + config TI_AEMIF tristate "Texas Instruments AEMIF driver" depends on ARCH_KEYSTONE || ARCH_DAVINCI diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index fdc83e4e1c8..77294fac69d 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_MEMORY) += memory-uclass.o obj-$(CONFIG_SANDBOX_MEMORY) += memory-sandbox.o obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o +obj-$(CONFIG_STM32_OMM) += stm32_omm.o obj-$(CONFIG_ATMEL_EBI) += atmel_ebi.o obj-$(CONFIG_TI_AEMIF) += ti-aemif.o ti-aemif-cs.o obj-$(CONFIG_TI_GPMC) += ti-gpmc.o diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c new file mode 100644 index 00000000000..d5a4e1b0683 --- /dev/null +++ b/drivers/memory/stm32_omm.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2025, STMicroelectronics - All Rights Reserved + */ + +#define LOG_CATEGORY UCLASS_NOP + +#include <clk.h> +#include <dm.h> +#include <regmap.h> +#include <reset.h> +#include <syscon.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/of_addr.h> +#include <dm/of_access.h> +#include <linux/bitfield.h> +#include <linux/ioport.h> +#include <mach/rif.h> + +/* OCTOSPI control register */ +#define OCTOSPIM_CR 0 +#define CR_MUXEN BIT(0) +#define CR_MUXENMODE_MASK GENMASK(1, 0) +#define CR_CSSEL_OVR_EN BIT(4) +#define CR_CSSEL_OVR_MASK GENMASK(6, 5) +#define CR_REQ2ACK_MASK GENMASK(23, 16) + +#define OMM_CHILD_NB 2 +#define OMM_CLK_NB 3 +#define OMM_RESET_NB 3 +#define NSEC_PER_SEC 1000000000L + +struct stm32_omm_plat { + phys_addr_t regs_base; + struct regmap *syscfg_regmap; + struct clk clk[OMM_CLK_NB]; + struct reset_ctl reset_ctl[OMM_RESET_NB]; + resource_size_t mm_ospi2_size; + u32 mux; + u32 cssel_ovr; + u32 req2ack; + u32 amcr_base; + u32 amcr_mask; + unsigned long clk_rate_max; + u8 nb_child; +}; + +static int stm32_omm_set_amcr(struct udevice *dev, bool set) +{ + struct stm32_omm_plat *plat = dev_get_plat(dev); + unsigned int amcr, read_amcr; + + amcr = plat->mm_ospi2_size / SZ_64M; + + if (set) + regmap_update_bits(plat->syscfg_regmap, plat->amcr_base, + plat->amcr_mask, amcr); + + /* read AMCR and check coherency with memory-map areas defined in DT */ + regmap_read(plat->syscfg_regmap, plat->amcr_base, &read_amcr); + read_amcr = read_amcr >> (ffs(plat->amcr_mask) - 1); + + if (amcr != read_amcr) { + dev_err(dev, "AMCR value not coherent with DT memory-map areas\n"); + return -EINVAL; + } + + return 0; +} + +static int stm32_omm_toggle_child_clock(struct udevice *dev, bool enable) +{ + struct stm32_omm_plat *plat = dev_get_plat(dev); + int i, ret; + + for (i = 0; i < plat->nb_child; i++) { + if (enable) { + ret = clk_enable(&plat->clk[i + 1]); + if (ret) { + dev_err(dev, "Can not enable clock\n"); + goto clk_error; + } + } else { + clk_disable(&plat->clk[i + 1]); + } + } + + return 0; + +clk_error: + while (i--) + clk_disable(&plat->clk[i + 1]); + + return ret; +} + +static int stm32_omm_disable_child(struct udevice *dev) +{ + struct stm32_omm_plat *plat = dev_get_plat(dev); + int ret; + u8 i; + + ret = stm32_omm_toggle_child_clock(dev, true); + if (ret) + return ret; + + for (i = 0; i < plat->nb_child; i++) { + /* reset OSPI to ensure CR_EN bit is set to 0 */ + reset_assert(&plat->reset_ctl[i + 1]); + udelay(2); + reset_deassert(&plat->reset_ctl[i + 1]); + } + + return stm32_omm_toggle_child_clock(dev, false); +} + +static int stm32_omm_configure(struct udevice *dev) +{ + struct stm32_omm_plat *plat = dev_get_plat(dev); + int ret; + u32 mux = 0; + u32 cssel_ovr = 0; + u32 req2ack = 0; + + /* Ensure both OSPI instance are disabled before configuring OMM */ + ret = stm32_omm_disable_child(dev); + if (ret) + return ret; + + ret = clk_enable(&plat->clk[0]); + if (ret) { + dev_err(dev, "Failed to enable OMM clock (%d)\n", ret); + return ret; + } + + reset_assert(&plat->reset_ctl[0]); + udelay(2); + reset_deassert(&plat->reset_ctl[0]); + + if (plat->mux & CR_MUXEN) { + if (plat->req2ack) { + req2ack = DIV_ROUND_UP(plat->req2ack, + NSEC_PER_SEC / plat->clk_rate_max) - 1; + if (req2ack > 256) + req2ack = 256; + } + + req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack); + clrsetbits_le32(plat->regs_base + OCTOSPIM_CR, CR_REQ2ACK_MASK, + req2ack); + + /* + * If the mux is enabled, the 2 OSPI clocks have to be + * always enabled + */ + ret = stm32_omm_toggle_child_clock(dev, true); + if (ret) + return ret; + } + + if (plat->cssel_ovr != 0xff) { + cssel_ovr = FIELD_PREP(CR_CSSEL_OVR_MASK, cssel_ovr); + cssel_ovr |= CR_CSSEL_OVR_EN; + clrsetbits_le32(plat->regs_base + OCTOSPIM_CR, CR_CSSEL_OVR_MASK, + cssel_ovr); + } + + mux = FIELD_PREP(CR_MUXENMODE_MASK, plat->mux); + clrsetbits_le32(plat->regs_base + OCTOSPIM_CR, CR_MUXENMODE_MASK, mux); + clk_disable(&plat->clk[0]); + + return stm32_omm_set_amcr(dev, true); +} + +static void stm32_omm_release_childs(ofnode *child_list, u8 nb_child) +{ + u8 i; + + for (i = 0; i < nb_child; i++) + stm32_rifsc_release_access(child_list[i]); +} + +static int stm32_omm_probe(struct udevice *dev) +{ + struct stm32_omm_plat *plat = dev_get_plat(dev); + ofnode child_list[OMM_CHILD_NB]; + ofnode child; + int ret; + u8 child_access_granted = 0; + bool child_access[OMM_CHILD_NB]; + + /* check child's access */ + for (child = ofnode_first_subnode(dev_ofnode(dev)); + ofnode_valid(child); + child = ofnode_next_subnode(child)) { + if (plat->nb_child > OMM_CHILD_NB) { + dev_err(dev, "Bad DT, found too much children\n"); + return -E2BIG; + } + + if (!ofnode_device_is_compatible(child, "st,stm32mp25-ospi")) + return -EINVAL; + + ret = stm32_rifsc_grant_access(child); + if (ret < 0 && ret != -EACCES) + return ret; + + child_access[plat->nb_child] = false; + if (!ret) { + child_access_granted++; + child_access[plat->nb_child] = true; + } + + child_list[plat->nb_child] = child; + plat->nb_child++; + } + + if (plat->nb_child != OMM_CHILD_NB) + return -EINVAL; + + /* check if OMM's resource access is granted */ + ret = stm32_rifsc_grant_access(dev_ofnode(dev)); + if (ret < 0 && ret != -EACCES) + goto end; + + /* All child's access are granted ? */ + if (!ret && child_access_granted == plat->nb_child) { + ret = stm32_omm_configure(dev); + if (ret) + goto end; + } else { + dev_dbg(dev, "Octo Memory Manager resource's access not granted\n"); + /* + * AMCR can't be set, so check if current value is coherent + * with memory-map areas defined in DT + */ + ret = stm32_omm_set_amcr(dev, false); + } + +end: + stm32_omm_release_childs(child_list, plat->nb_child); + stm32_rifsc_release_access(dev_ofnode(dev)); + + return ret; +} + +static int stm32_omm_of_to_plat(struct udevice *dev) +{ + struct stm32_omm_plat *plat = dev_get_plat(dev); + static const char * const clocks_name[] = {"omm", "ospi1", "ospi2"}; + static const char * const mm_name[] = { "ospi1", "ospi2" }; + static const char * const resets_name[] = {"omm", "ospi1", "ospi2"}; + struct resource res, res1, mm_res; + struct ofnode_phandle_args args; + struct udevice *child; + unsigned long clk_rate; + struct clk child_clk; + int ret, idx; + u8 i; + + plat->regs_base = dev_read_addr(dev); + if (plat->regs_base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = dev_read_resource_byname(dev, "memory_map", &mm_res); + if (ret) { + dev_err(dev, "can't get omm_mm mmap resource(ret = %d)!\n", ret); + return ret; + } + + for (i = 0; i < OMM_CLK_NB; i++) { + ret = clk_get_by_name(dev, clocks_name[i], &plat->clk[i]); + if (ret < 0) { + dev_err(dev, "Can't find I/O manager clock %s\n", clocks_name[i]); + return ret; + } + + ret = reset_get_by_name(dev, resets_name[i], &plat->reset_ctl[i]); + if (ret < 0) { + dev_err(dev, "Can't find I/O manager reset %s\n", resets_name[i]); + return ret; + } + } + + /* parse children's clock */ + plat->clk_rate_max = 0; + device_foreach_child(child, dev) { + ret = clk_get_by_index(child, 0, &child_clk); + if (ret) { + dev_err(dev, "Failed to get clock for %s\n", + dev_read_name(child)); + return ret; + } + + clk_rate = clk_get_rate(&child_clk); + if (!clk_rate) { + dev_err(dev, "Invalid clock rate\n"); + return -EINVAL; + } + + if (clk_rate > plat->clk_rate_max) + plat->clk_rate_max = clk_rate; + } + + plat->mux = dev_read_u32_default(dev, "st,omm-mux", 0); + plat->req2ack = dev_read_u32_default(dev, "st,omm-req2ack-ns", 0); + plat->cssel_ovr = dev_read_u32_default(dev, "st,omm-cssel-ovr", 0xff); + plat->mm_ospi2_size = 0; + + for (i = 0; i < 2; i++) { + idx = dev_read_stringlist_search(dev, "memory-region-names", + mm_name[i]); + if (idx < 0) + continue; + + /* res1 only used on second loop iteration */ + res1.start = res.start; + res1.end = res.end; + + dev_read_phandle_with_args(dev, "memory-region", NULL, 0, idx, + &args); + ret = ofnode_read_resource(args.node, 0, &res); + if (ret) { + dev_err(dev, "unable to resolve memory region\n"); + return ret; + } + + /* check that memory region fits inside OMM memory map area */ + if (!resource_contains(&mm_res, &res)) { + dev_err(dev, "%s doesn't fit inside OMM memory map area\n", + mm_name[i]); + dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n", + res.start, res.end, + mm_res.start, mm_res.end); + + return -EFAULT; + } + + if (i == 1) { + plat->mm_ospi2_size = resource_size(&res); + + /* check that OMM memory region 1 doesn't overlap memory region 2 */ + if (resource_overlaps(&res, &res1)) { + dev_err(dev, "OMM memory-region %s overlaps memory region %s\n", + mm_name[0], mm_name[1]); + dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n", + res1.start, res1.end, res.start, res.end); + + return -EFAULT; + } + } + } + + plat->syscfg_regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-amcr"); + if (IS_ERR(plat->syscfg_regmap)) { + dev_err(dev, "Failed to get st,syscfg-amcr property\n"); + ret = PTR_ERR(plat->syscfg_regmap); + return ret; + } + + ret = dev_read_u32_index(dev, "st,syscfg-amcr", 1, &plat->amcr_base); + if (ret) { + dev_err(dev, "Failed to get st,syscfg-amcr base\n"); + return ret; + } + + ret = dev_read_u32_index(dev, "st,syscfg-amcr", 2, &plat->amcr_mask); + if (ret) { + dev_err(dev, "Failed to get st,syscfg-amcr mask\n"); + return ret; + } + + return 0; +}; + +static int stm32_omm_bind(struct udevice *dev) +{ + int ret = 0, err = 0; + ofnode node; + + for (node = ofnode_first_subnode(dev_ofnode(dev)); + ofnode_valid(node); + node = ofnode_next_subnode(node)) { + const char *node_name = ofnode_get_name(node); + + if (!ofnode_is_enabled(node) || stm32_rifsc_grant_access(node)) { + dev_dbg(dev, "%s failed to bind\n", node_name); + continue; + } + + err = lists_bind_fdt(dev, node, NULL, NULL, + gd->flags & GD_FLG_RELOC ? false : true); + if (err && !ret) { + ret = err; + dev_dbg(dev, "%s: ret=%d\n", node_name, ret); + } + } + + if (ret) + dev_dbg(dev, "Some drivers failed to bind\n"); + + return ret; +} + +static const struct udevice_id stm32_omm_ids[] = { + { .compatible = "st,stm32mp25-omm", }, + {}, +}; + +U_BOOT_DRIVER(stm32_omm) = { + .name = "stm32_omm", + .id = UCLASS_NOP, + .probe = stm32_omm_probe, + .of_match = stm32_omm_ids, + .of_to_plat = stm32_omm_of_to_plat, + .plat_auto = sizeof(struct stm32_omm_plat), + .bind = stm32_omm_bind, +}; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 29b84430ff5..e3a207866ea 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -440,6 +440,7 @@ config STM32MP_FUSE config K3_FUSE bool "Enable TI K3 fuse wrapper providing the fuse API" depends on MISC && CMD_FUSE && CMD_FUSE_WRITEBUFF + depends on ARCH_K3 help If you say Y here, you will get support for the fuse API (OTP) for TI K3 architecture. diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c index 66803f4b997..2928cf75f89 100644 --- a/drivers/misc/fs_loader.c +++ b/drivers/misc/fs_loader.c @@ -148,7 +148,7 @@ static int _request_firmware_prepare(struct udevice *dev, */ static int fw_get_filesystem_firmware(struct udevice *dev) { - loff_t actread; + loff_t actread = 0; char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume; int ret; diff --git a/drivers/misc/imx8/scu_api.c b/drivers/misc/imx8/scu_api.c index 8985ab6584d..d9cc7acb970 100644 --- a/drivers/misc/imx8/scu_api.c +++ b/drivers/misc/imx8/scu_api.c @@ -1286,3 +1286,34 @@ int sc_seco_secvio_dgo_config(sc_ipc_t ipc, u8 id, u8 access, u32 *data) return ret; } + +int sc_seco_commit(sc_ipc_t ipc, u32 *info) +{ + struct udevice *dev = gd->arch.scu_dev; + struct sc_rpc_msg_s msg; + int size = sizeof(struct sc_rpc_msg_s); + int ret; + + /* Fill in header */ + RPC_VER(&msg) = SC_RPC_VERSION; + RPC_SIZE(&msg) = 2U; + RPC_SVC(&msg) = (u8)SC_RPC_SVC_SECO; + RPC_FUNC(&msg) = (u8)SECO_FUNC_COMMIT; + + /* Fill in send message */ + RPC_U32(&msg, 0U) = *info; + + /* Call RPC */ + ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size); + if (ret) + return ret; + + /* Copy out result */ + ret = (int)RPC_R8(&msg); + + /* Copy out receive message */ + if (!ret) + *info = RPC_U32(&msg, 0U); + + return ret; +} diff --git a/drivers/misc/mpfs_syscontroller.c b/drivers/misc/mpfs_syscontroller.c index 41e80815ab5..f608d5518b0 100644 --- a/drivers/misc/mpfs_syscontroller.c +++ b/drivers/misc/mpfs_syscontroller.c @@ -22,7 +22,27 @@ #include <misc.h> #include <mpfs-mailbox.h> +#define SYS_SPI_CMD 0x50 +#define SYS_SPI_MAILBOX_DATA_LEN 17 +#define SYS_SPI_MAILBOX_SRC_OFFSET 8 +#define SYS_SPI_MAILBOX_LENGTH_OFFSET 12 +#define SYS_SPI_MAILBOX_FREQ_OFFSET 16 +#define SYS_SPI_MAILBOX_FREQ 3 +#define SPI_FLASH_ADDR 0x400 + /* Descriptor table */ +#define START_OFFSET 4 +#define END_OFFSET 8 +#define SIZE_OFFSET 12 +#define DESC_NEXT 12 +#define DESC_RESERVED_SIZE 0 +#define DESC_SIZE 16 + +#define DESIGN_MAGIC_0 0x4d /* 'M' */ +#define DESIGN_MAGIC_1 0x43 /* 'C'*/ +#define DESIGN_MAGIC_2 0x48 /* 'H'*/ +#define DESIGN_MAGIC_3 0x50 /* 'P'*/ + #define CMD_OPCODE 0x0u #define CMD_DATA_SIZE 0U #define CMD_DATA NULL @@ -109,6 +129,186 @@ int mpfs_syscontroller_read_sernum(struct mpfs_sys_serv *sys_serv_priv, u8 *devi } EXPORT_SYMBOL(mpfs_syscontroller_read_sernum); +static u16 mpfs_syscontroller_service_spi_copy(struct mpfs_sys_serv *sys_serv_priv, u64 dst_addr, u32 src_addr, u32 length) +{ + int ret; + u32 mailbox_format[SYS_SPI_MAILBOX_DATA_LEN]; + + *(u64 *)mailbox_format = dst_addr; + mailbox_format[SYS_SPI_MAILBOX_SRC_OFFSET/4] = src_addr; + mailbox_format[SYS_SPI_MAILBOX_LENGTH_OFFSET/4] = length; + mailbox_format[SYS_SPI_MAILBOX_FREQ_OFFSET/4] = SYS_SPI_MAILBOX_FREQ; + + struct mpfs_mss_response response = { + .resp_status = 0U, + .resp_msg = mailbox_format, + .resp_size = RESP_BYTES}; + struct mpfs_mss_msg msg = { + .cmd_opcode = SYS_SPI_CMD, + .cmd_data_size = SYS_SPI_MAILBOX_DATA_LEN, + .response = &response, + .cmd_data = (u8 *)mailbox_format, + .mbox_offset = MBOX_OFFSET, + .resp_offset = RESP_OFFSET}; + + ret = mpfs_syscontroller_run_service(sys_serv_priv->sys_controller, &msg); + if (ret) { + dev_err(sys_serv_priv->sys_controller->chan.dev, "Service failed: %d, abort. Failure: %u\n", ret, msg.response->resp_status); + } + + return ret; +} + +static u16 mpfs_syscontroller_get_dtbo_desc_header(struct mpfs_sys_serv *sys_serv_priv, u8 *desc_data, u32 desc_addr) +{ + u32 length, no_of_descs; + int ret = -ENOENT; + + /* Get first four bytes to calculate length */ + ret = mpfs_syscontroller_service_spi_copy(sys_serv_priv, (u64)desc_data, desc_addr, BYTES_4); + if (!ret) { + no_of_descs = *((u32 *)desc_data); + if (no_of_descs) { + length = DESC_SIZE + ((no_of_descs - 1) * DESC_SIZE); + ret = mpfs_syscontroller_service_spi_copy(sys_serv_priv, (u64)desc_data, desc_addr, + length); + } + } + + return ret; +} + +static u8 *mpfs_syscontroller_get_dtbo(struct mpfs_sys_serv *sys_serv_priv, u32 start_addr, u32 size) +{ + int ret; + u8 *dtbo; + + /* Intentionally never freed, even on success so that u-boot "userspace" can access it. */ + dtbo = (u8 *)malloc(size); + + ret = mpfs_syscontroller_service_spi_copy(sys_serv_priv, (u64)dtbo, start_addr, size); + if (ret) { + free(dtbo); + dtbo = NULL; + } + + return dtbo; +} + +static void mpfs_syscontroller_parse_desc_header(struct mpfs_sys_serv *sys_serv_priv, u8 *desc_header, u8 *no_of_dtbo, u32 *dtbos_size) +{ + u32 dtbo_desc_start_addr; + u32 dtbo_desc_size; + u32 no_of_descs; + u16 i; + u8 dtbo_name[16]; + u8 dtbo_addr[20]; + u8 *desc; + u8 *dtbo; + + no_of_descs = *((u32 *)desc_header); + + for (i = 0; i < no_of_descs; i++) { + desc = &desc_header[START_OFFSET + (DESC_NEXT * i)]; + /* + * The dtbo info structure contains addresses that are relative + * to the start of structure, so the offset of the structure in + * flash must be added to get the actual start address. + */ + dtbo_desc_start_addr = *((u32 *)desc) + SPI_FLASH_ADDR; + + desc = &desc_header[SIZE_OFFSET + (DESC_NEXT * i)]; + dtbo_desc_size = *((u32 *)desc); + + dtbo = mpfs_syscontroller_get_dtbo(sys_serv_priv, dtbo_desc_start_addr, dtbo_desc_size); + if (dtbo) { + sprintf(dtbo_name, "dtbo_image%d", *no_of_dtbo); + sprintf(dtbo_addr, "0x%llx", (u64)dtbo); + env_set(dtbo_name, dtbo_addr); + ++*no_of_dtbo; + *dtbos_size += dtbo_desc_size; + } + } +} + +void mpfs_syscontroller_process_dtbo(struct mpfs_sys_serv *sys_serv_priv) +{ + u32 desc_length; + u32 dtbo_desc_addr; + u32 dtbo_addr[5]; + u16 i, hart, no_of_harts; + u8 design_info_desc[256]; + u8 dtbo_desc_data[256]; + u8 no_of_dtbos[8]; + u8 dtbo_size[8]; + u8 *desc; + u8 no_of_dtbo = 0; + u32 dtbos_size = 0; + int ret; + + /* Read first 10 bytes to verify the descriptor is found or not */ + ret = mpfs_syscontroller_service_spi_copy(sys_serv_priv, (u64)design_info_desc, SPI_FLASH_ADDR, 10); + if (ret) { + sprintf(no_of_dtbos, "%d", no_of_dtbo); + env_set("no_of_overlays", no_of_dtbos); + sprintf(dtbo_size, "%d", dtbos_size); + env_set("dtbo_size", dtbo_size); + return; + } + + if (design_info_desc[0] != DESIGN_MAGIC_0 || + design_info_desc[1] != DESIGN_MAGIC_1 || + design_info_desc[2] != DESIGN_MAGIC_2 || + design_info_desc[3] != DESIGN_MAGIC_3) { + dev_dbg(sys_serv_priv->dev, "magic not found in desc structure.\n"); + sprintf(no_of_dtbos, "%d", no_of_dtbo); + env_set("no_of_overlays", no_of_dtbos); + sprintf(dtbo_size, "%d", dtbos_size); + env_set("dtbo_size", dtbo_size); + return; + } + desc_length = *((u32 *)&design_info_desc[4]); + /* Read Design descriptor */ + ret = mpfs_syscontroller_service_spi_copy(sys_serv_priv, (u64)design_info_desc, + SPI_FLASH_ADDR, desc_length); + if (ret) + return; + + no_of_harts = *((u16 *)&design_info_desc[10]); + + for (hart = 0; hart < no_of_harts; hart++) { + /* Start address of DTBO descriptor */ + desc = &design_info_desc[(0x4 * hart) + 0xc]; + + dtbo_desc_addr = *((u32 *)desc); + dtbo_addr[hart] = dtbo_desc_addr; + + if (!dtbo_addr[hart]) + continue; + + for (i = 0; i < hart; i++) { + if (dtbo_addr[hart] == dtbo_addr[i]) + continue; + } + + if (hart && hart == i) + continue; + + dtbo_desc_addr += SPI_FLASH_ADDR; + ret = mpfs_syscontroller_get_dtbo_desc_header(sys_serv_priv, dtbo_desc_data, + dtbo_desc_addr); + if (ret) + continue; + else + mpfs_syscontroller_parse_desc_header(sys_serv_priv, dtbo_desc_data, &no_of_dtbo, &dtbos_size); + } + sprintf(no_of_dtbos, "%d", no_of_dtbo); + env_set("no_of_overlays", no_of_dtbos); + sprintf(dtbo_size, "%d", dtbos_size); + env_set("dtbo_size", dtbo_size); +} +EXPORT_SYMBOL(mpfs_syscontroller_process_dtbo); + static int mpfs_syscontroller_probe(struct udevice *dev) { struct mpfs_syscontroller_priv *sys_controller = dev_get_priv(dev); diff --git a/drivers/misc/npcm_host_intf.c b/drivers/misc/npcm_host_intf.c index 58bab888c3c..e3b0663625b 100644 --- a/drivers/misc/npcm_host_intf.c +++ b/drivers/misc/npcm_host_intf.c @@ -22,6 +22,8 @@ /* ESPI Register offsets */ #define ESPICFG 0x4 #define ESPIHINDP 0x80 +#define ESPI_TEN 0xF0 +#define ESPI_ENG 0xF1 /* MFSEL bit fileds */ #define MFSEL1_LPCSEL BIT(26) @@ -40,10 +42,23 @@ #define AUTO_HS2 BIT(12) #define AUTO_HS3 BIT(16) +#define ESPI_TEN_ENABLE 0x55 +#define ESPI_TEN_DISABLE 0 + +/* KCS/BPC interrupt control */ +#define BPCFEN 0x46 +#define FRIE BIT(3) +#define HRIE BIT(4) +#define KCS1CTL 0x18 +#define KCS2CTL 0x2a +#define KCS3CTL 0x3c +#define IBFIE BIT(0) +#define OBEIE BIT(1) + static int npcm_host_intf_bind(struct udevice *dev) { struct regmap *syscon; - void __iomem *base; + void __iomem *base, *kcs_base; u32 ch_supp, val; u32 ioaddr; const char *type; @@ -83,6 +98,13 @@ static int npcm_host_intf_bind(struct udevice *dev) val &= ~(CHSUPP_MASK | IOMODE_MASK | MAXFREQ_MASK); val |= IOMODE_SDQ | MAXFREQ_33MHZ | FIELD_PREP(CHSUPP_MASK, ch_supp); writel(val, base + ESPICFG); + + if (device_is_compatible(dev, "nuvoton,npcm845-host-intf")) { + /* Workaround: avoid eSPI module getting into wrong state */ + writeb(ESPI_TEN_ENABLE, base + ESPI_TEN); + writeb(BIT(6), base + ESPI_ENG); + writeb(ESPI_TEN_DISABLE, base + ESPI_TEN); + } } else if (!strcmp(type, "lpc")) { /* Select LPC pin function */ regmap_update_bits(syscon, MFSEL4, MFSEL4_ESPISEL, 0); @@ -92,6 +114,15 @@ static int npcm_host_intf_bind(struct udevice *dev) /* Release host wait */ setbits_8(SMC_CTL_REG_ADDR, SMC_CTL_HOSTWAIT); + kcs_base = dev_read_addr_index_ptr(dev, 1); + if (kcs_base) { + /* Disable KCS/BPC interrupts */ + clrbits_8(kcs_base + BPCFEN, FRIE | HRIE); + clrbits_8(kcs_base + KCS1CTL, IBFIE | OBEIE); + clrbits_8(kcs_base + KCS2CTL, IBFIE | OBEIE); + clrbits_8(kcs_base + KCS3CTL, IBFIE | OBEIE); + } + return 0; } diff --git a/drivers/mmc/adi_sdhci.c b/drivers/mmc/adi_sdhci.c index 65a22cefb71..f58897b5218 100644 --- a/drivers/mmc/adi_sdhci.c +++ b/drivers/mmc/adi_sdhci.c @@ -15,6 +15,7 @@ #include <malloc.h> #include <sdhci.h> #include <asm/cache.h> +#include <linux/sizes.h> /* 400KHz is max freq for card ID etc. Use that as min */ #define EMMC_MIN_FREQ 400000 diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c index 377e6a887df..036e798f374 100644 --- a/drivers/mmc/cv1800b_sdhci.c +++ b/drivers/mmc/cv1800b_sdhci.c @@ -19,6 +19,7 @@ struct cv1800b_sdhci_plat { struct mmc mmc; }; +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static void cv1800b_set_tap_delay(struct sdhci_host *host, u16 tap) { sdhci_writel(host, PHY_TX_SRC_INVERT | tap << 16, SDHCI_PHY_TX_RX_DLY); @@ -31,7 +32,6 @@ static void cv1800b_sdhci_reset(struct sdhci_host *host, u8 mask) udelay(10); } -#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int cv1800b_execute_tuning(struct mmc *mmc, u8 opcode) { struct sdhci_host *host = dev_get_priv(mmc->dev); diff --git a/drivers/mmc/iproc_sdhci.c b/drivers/mmc/iproc_sdhci.c index 7ab74ff117a..654672a546f 100644 --- a/drivers/mmc/iproc_sdhci.c +++ b/drivers/mmc/iproc_sdhci.c @@ -182,7 +182,7 @@ static int sdhci_iproc_execute_tuning(struct mmc *mmc, u8 opcode) u32 ctrl; u32 blocksize = SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 64); struct sdhci_host *host = dev_get_priv(mmc->dev); - char tuning_loop_counter = MAX_TUNING_LOOP; + s8 tuning_loop_counter = MAX_TUNING_LOOP; int ret = 0; sdhci_start_tuning(host); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 5f2efbe6df9..ec61ed92e86 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -104,8 +104,7 @@ __weak int board_mmc_getcd(struct mmc *mmc) return -1; } #endif - -#ifdef CONFIG_MMC_TRACE +#if IS_ENABLED(CONFIG_MMC_TRACE) void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) { printf("CMD_SEND:%d\n", cmd->cmdidx); @@ -125,21 +124,21 @@ void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) printf("\t\tMMC_RSP_NONE\n"); break; case MMC_RSP_R1: - printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08x \n", + printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08x\n", cmd->response[0]); break; case MMC_RSP_R1b: - printf("\t\tMMC_RSP_R1b\t\t 0x%08x \n", + printf("\t\tMMC_RSP_R1b\t\t 0x%08x\n", cmd->response[0]); break; case MMC_RSP_R2: - printf("\t\tMMC_RSP_R2\t\t 0x%08x \n", + printf("\t\tMMC_RSP_R2\t\t 0x%08x\n", cmd->response[0]); - printf("\t\t \t\t 0x%08x \n", + printf("\t\t \t\t 0x%08x\n", cmd->response[1]); - printf("\t\t \t\t 0x%08x \n", + printf("\t\t \t\t 0x%08x\n", cmd->response[2]); - printf("\t\t \t\t 0x%08x \n", + printf("\t\t \t\t 0x%08x\n", cmd->response[3]); printf("\n"); printf("\t\t\t\t\tDUMPING DATA\n"); @@ -154,7 +153,7 @@ void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) } break; case MMC_RSP_R3: - printf("\t\tMMC_RSP_R3,4\t\t 0x%08x \n", + printf("\t\tMMC_RSP_R3,4\t\t 0x%08x\n", cmd->response[0]); break; default: @@ -1547,7 +1546,7 @@ static int sd_select_bus_width(struct mmc *mmc, int w) } #endif -#if CONFIG_IS_ENABLED(MMC_WRITE) +#if CONFIG_IS_ENABLED(MMC_WRITE) && !CONFIG_IS_ENABLED(MMC_TINY) static int sd_read_ssr(struct mmc *mmc) { static const unsigned int sd_au_size[] = { @@ -3190,7 +3189,7 @@ static int mmc_probe(struct bd_info *bis) int mmc_initialize(struct bd_info *bis) { - static int initialized = 0; + static int initialized; int ret; if (initialized) /* Avoid initializing mmc multiple times */ return 0; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 92bc72b267c..ae742080643 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -651,6 +651,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode) printf("Couldn't get temperature for tuning\n"); return ret; } + temperature /= 1000; val = readl(&mmc_base->dll); val |= DLL_SWT; writel(val, &mmc_base->dll); diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c index 9a92b8437a6..ead96dc0c91 100644 --- a/drivers/mmc/sdhci-cadence6.c +++ b/drivers/mmc/sdhci-cadence6.c @@ -180,10 +180,8 @@ static int sdhci_cdns6_reset_phy_dll(struct sdhci_cdns_plat *plat, bool reset) int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 mode) { - DECLARE_GLOBAL_DATA_PTR; struct sdhci_cdns6_phy_cfg *sdhci_cdns6_phy_cfgs; struct sdhci_cdns6_ctrl_cfg *sdhci_cdns6_ctrl_cfgs; - const fdt32_t *prop; u32 tmp; int i, ret; @@ -216,19 +214,11 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m return -EINVAL; } - for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++) { - prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), - sdhci_cdns6_phy_cfgs[i].property, NULL); - if (prop) - sdhci_cdns6_phy_cfgs[i].val = *prop; - } + for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++) + dev_read_u32(dev, sdhci_cdns6_phy_cfgs[i].property, &sdhci_cdns6_phy_cfgs[i].val); - for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++) { - prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), - sdhci_cdns6_ctrl_cfgs[i].property, NULL); - if (prop) - sdhci_cdns6_ctrl_cfgs[i].val = *prop; - } + for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++) + dev_read_u32(dev, sdhci_cdns6_ctrl_cfgs[i].property, &sdhci_cdns6_ctrl_cfgs[i].val); /* Switch On the DLL Reset */ sdhci_cdns6_reset_phy_dll(plat, true); diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 3b86bc9b18c..db4e0129c2e 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -29,7 +29,9 @@ struct socfpga_dwmci_plat { /* socfpga implmentation specific driver private data */ struct dwmci_socfpga_priv_data { + struct udevice *dev; struct dwmci_host host; + struct clk mmc_clk_ciu; unsigned int drvsel; unsigned int smplsel; }; @@ -51,28 +53,23 @@ static void socfpga_dwmci_reset(struct udevice *dev) static int socfpga_dwmci_clksel(struct dwmci_host *host) { struct dwmci_socfpga_priv_data *priv = host->priv; + int ret; + u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) | ((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT); - /* Get clock manager base address */ - struct udevice *clkmgr_dev; - int ret = uclass_get_device_by_name(UCLASS_CLK, "clock-controller@ffd10000", &clkmgr_dev); - + ret = clk_get_by_name(priv->dev, "ciu", &priv->mmc_clk_ciu); if (ret) { - printf("Failed to get clkmgr device: %d\n", ret); + debug("%s: Failed to get SDMMC clock from dts\n", __func__); return ret; } - fdt_addr_t clkmgr_base = dev_read_addr(clkmgr_dev); - - if (clkmgr_base == FDT_ADDR_T_NONE) { - printf("Failed to read base address from clkmgr DT node\n"); - return -EINVAL; - } - /* Disable SDMMC clock. */ - clrbits_le32(clkmgr_base + CLKMGR_PERPLL_EN, - CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + ret = clk_disable(&priv->mmc_clk_ciu); + if (ret) { + printf("%s: Failed to disable SDMMC clock\n", __func__); + return ret; + } debug("%s: drvsel %d smplsel %d\n", __func__, priv->drvsel, priv->smplsel); @@ -92,8 +89,11 @@ static int socfpga_dwmci_clksel(struct dwmci_host *host) #endif /* Enable SDMMC clock */ - setbits_le32(clkmgr_base + CLKMGR_PERPLL_EN, - CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + ret = clk_enable(&priv->mmc_clk_ciu); + if (ret) { + printf("%s: Failed to enable SDMMC clock\n", __func__); + return ret; + } return 0; } @@ -169,6 +169,7 @@ static int socfpga_dwmmc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + priv->dev = dev; int ret; ret = socfpga_dwmmc_get_clk_rate(dev); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index e505f797949..06941a4fa8b 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -41,6 +41,7 @@ config MTD_BLOCK config SYS_MTDPARTS_RUNTIME bool "Allow MTDPARTS to be configured at runtime" + depends on !COMPILE_TEST help This option allows to call the function board_mtdparts_default to dynamically build the variables mtdids and mtdparts at runtime. diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 45699b4a477..2ec968c85ff 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -936,12 +936,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi, ubi_err(ubi, "bad data_size"); goto bad; } - } else if (lnum == used_ebs - 1) { - if (data_size == 0) { - ubi_err(ubi, "bad data_size at last LEB"); - goto bad; - } - } else { + } else if (lnum != used_ebs - 1) { ubi_err(ubi, "too high lnum"); goto bad; } diff --git a/drivers/mtd/ubispl/ubispl.c b/drivers/mtd/ubispl/ubispl.c index 9face5fae15..0143caa051d 100644 --- a/drivers/mtd/ubispl/ubispl.c +++ b/drivers/mtd/ubispl/ubispl.c @@ -779,7 +779,7 @@ static int ubi_scan_fastmap(struct ubi_scan_info *ubi, * that already so we merily copy it over. */ if (pnum == fm_anchor) - memcpy(vh, ubi->blockinfo + pnum, sizeof(*fm)); + memcpy(vh, ubi->blockinfo + pnum, sizeof(*vh)); if (i == 0) { if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) { diff --git a/drivers/net/dwc_eth_qos_adi.c b/drivers/net/dwc_eth_qos_adi.c index 0e6a901e303..fee50a88156 100644 --- a/drivers/net/dwc_eth_qos_adi.c +++ b/drivers/net/dwc_eth_qos_adi.c @@ -10,6 +10,7 @@ #include <clk.h> #include <dm.h> +#include <env.h> #include <net.h> #include <phy.h> #include <reset.h> diff --git a/drivers/net/e1000_spi.c b/drivers/net/e1000_spi.c index 1e830b99f1d..33d38b57824 100644 --- a/drivers/net/e1000_spi.c +++ b/drivers/net/e1000_spi.c @@ -472,6 +472,7 @@ static int do_e1000_spi_checksum(struct cmd_tbl *cmdtp, struct e1000_hw *hw, uint16_t i, length, checksum = 0, checksum_reg; uint16_t *buffer; bool upd; + int ret = 0; if (argc == 0) upd = 0; @@ -493,14 +494,15 @@ static int do_e1000_spi_checksum(struct cmd_tbl *cmdtp, struct e1000_hw *hw, /* Acquire the EEPROM */ if (e1000_acquire_eeprom(hw)) { E1000_ERR(hw, "EEPROM SPI cannot be acquired!\n"); - return 1; + ret = 1; + goto free_exit; } /* Read the EEPROM */ if (e1000_spi_eeprom_dump(hw, buffer, 0, length, true) < 0) { E1000_ERR(hw, "Interrupted!\n"); - e1000_release_eeprom(hw); - return 1; + ret = 1; + goto release_exit; } /* Compute the checksum and read the expected value */ @@ -513,8 +515,8 @@ static int do_e1000_spi_checksum(struct cmd_tbl *cmdtp, struct e1000_hw *hw, if (checksum_reg == checksum) { printf("%s: INFO: EEPROM checksum is correct! (0x%04hx)\n", hw->name, checksum); - e1000_release_eeprom(hw); - return 0; + ret = 0; + goto release_exit; } /* Hrm, verification failed, print an error */ @@ -524,8 +526,8 @@ static int do_e1000_spi_checksum(struct cmd_tbl *cmdtp, struct e1000_hw *hw, /* If they didn't ask us to update it, just return an error */ if (!upd) { - e1000_release_eeprom(hw); - return 1; + ret = 1; + goto release_exit; } /* Ok, correct it! */ @@ -534,12 +536,15 @@ static int do_e1000_spi_checksum(struct cmd_tbl *cmdtp, struct e1000_hw *hw, if (e1000_spi_eeprom_program(hw, &buffer[i], i * sizeof(uint16_t), sizeof(uint16_t), true)) { E1000_ERR(hw, "Interrupted!\n"); - e1000_release_eeprom(hw); - return 1; + ret = 1; + /* goto release_exit; */ } +release_exit: e1000_release_eeprom(hw); - return 0; +free_exit: + free(buffer); + return ret; } int do_e1000_spi(struct cmd_tbl *cmdtp, struct e1000_hw *hw, diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c index 63fe4b2d33c..f0e7c0eca42 100644 --- a/drivers/net/fm/eth.c +++ b/drivers/net/fm/eth.c @@ -169,7 +169,7 @@ static void bmi_rx_port_disable(struct fm_bmi_rx_port *rx_port) /* wait until the rx port is not busy */ while ((in_be32(&rx_port->fmbm_rst) & FMBM_RST_BSY) && timeout--) ; - if (!timeout) + if (timeout == -1) printf("%s - timeout\n", __func__); } @@ -199,7 +199,7 @@ static void bmi_tx_port_disable(struct fm_bmi_tx_port *tx_port) /* wait until the tx port is not busy */ while ((in_be32(&tx_port->fmbm_tst) & FMBM_TST_BSY) && timeout--) ; - if (!timeout) + if (timeout == -1) printf("%s - timeout\n", __func__); } @@ -727,12 +727,15 @@ static int fm_eth_bind(struct udevice *dev) char mac_name[11]; u32 fm, num; + if (!dev) + return -EINVAL; + if (ofnode_read_u32(ofnode_get_parent(dev_ofnode(dev)), "cell-index", &fm)) { printf("FMan node property cell-index missing\n"); return -EINVAL; } - if (dev && dev_read_u32(dev, "cell-index", &num)) { + if (dev_read_u32(dev, "cell-index", &num)) { printf("FMan MAC node property cell-index missing\n"); return -EINVAL; } diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c index 26425d94ae5..1ad3c053593 100644 --- a/drivers/net/fm/memac_phy.c +++ b/drivers/net/fm/memac_phy.c @@ -46,7 +46,7 @@ static int memac_wait_until_free(struct memac_mdio_controller *regs) while ((memac_in_32(®s->mdio_stat) & MDIO_STAT_BSY) && timeout--) ; - if (!timeout) { + if (timeout == -1) { printf("timeout waiting for MDIO bus to be free\n"); return -ETIMEDOUT; } @@ -64,7 +64,7 @@ static int memac_wait_until_done(struct memac_mdio_controller *regs) while ((memac_in_32(®s->mdio_stat) & MDIO_STAT_BSY) && timeout--) ; - if (!timeout) { + if (timeout == -1) { printf("timeout waiting for MDIO operation to complete\n"); return -ETIMEDOUT; } diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index 86daf0fb2bb..c8ed702f50a 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -366,8 +366,8 @@ static int mc_fixup_dpc_mac_addr(void *blob, int dpmac_id, noff = fdt_add_subnode(blob, nodeoffset, mac_name); if (noff < 0) { printf("fdt_add_subnode: err=%s\n", - fdt_strerror(err)); - return err; + fdt_strerror(noff)); + return noff; } /* add default property of fixed link */ @@ -1178,6 +1178,7 @@ err_get_api_ver: dflt_dpio->dpio_id); err_create: free(dflt_dpio); + dflt_dpio = NULL; err_calloc: return err; } @@ -1186,6 +1187,9 @@ static int dpio_exit(void) { int err; + if (!dflt_dpio) + return -ENODEV; + err = dpio_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle); if (err < 0) { printf("dpio_disable() failed: %d\n", err); @@ -1211,8 +1215,8 @@ static int dpio_exit(void) printf("Exit: DPIO.%d\n", dflt_dpio->dpio_id); #endif - if (dflt_dpio) - free(dflt_dpio); + free(dflt_dpio); + dflt_dpio = NULL; return 0; err: @@ -1434,6 +1438,7 @@ err_close: err_open: err_create: free(dflt_dpbp); + dflt_dpbp = NULL; err_calloc: return err; } @@ -1442,6 +1447,9 @@ static int dpbp_exit(void) { int err; + if (!dflt_dpbp) + return -ENODEV; + err = dpbp_destroy(dflt_mc_io, dflt_dprc_handle, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_id); if (err < 0) { @@ -1453,8 +1461,8 @@ static int dpbp_exit(void) printf("Exit: DPBP.%d\n", dflt_dpbp->dpbp_attr.id); #endif - if (dflt_dpbp) - free(dflt_dpbp); + free(dflt_dpbp); + dflt_dpbp = NULL; return 0; err: @@ -1531,6 +1539,7 @@ err_get_version: dflt_dpni->dpni_id); err_create: free(dflt_dpni); + dflt_dpni = NULL; err_calloc: return err; } @@ -1539,6 +1548,9 @@ static int dpni_exit(void) { int err; + if (!dflt_dpni) + return -ENODEV; + err = dpni_destroy(dflt_mc_io, dflt_dprc_handle, MC_CMD_NO_FLAGS, dflt_dpni->dpni_id); if (err < 0) { @@ -1550,8 +1562,8 @@ static int dpni_exit(void) printf("Exit: DPNI.%d\n", dflt_dpni->dpni_id); #endif - if (dflt_dpni) - free(dflt_dpni); + free(dflt_dpni); + dflt_dpni = NULL; return 0; err: diff --git a/drivers/net/fsl_enetc_netc_blk_ctrl.c b/drivers/net/fsl_enetc_netc_blk_ctrl.c index 46b68d3d8a4..fecd66eb15a 100644 --- a/drivers/net/fsl_enetc_netc_blk_ctrl.c +++ b/drivers/net/fsl_enetc_netc_blk_ctrl.c @@ -293,7 +293,7 @@ static int netc_blk_ctrl_probe(struct udevice *dev) err = clk_prepare_enable(ipg_clk); if (err) { dev_err(dev, "Enable ipg clock failed\n"); - return PTR_ERR(ipg_clk); + return err; } regs = dev_read_addr_name(dev, "ierb"); diff --git a/drivers/net/mdio_mux_meson_gxl.c b/drivers/net/mdio_mux_meson_gxl.c index 8ef3ae598b7..31898ed437e 100644 --- a/drivers/net/mdio_mux_meson_gxl.c +++ b/drivers/net/mdio_mux_meson_gxl.c @@ -19,6 +19,7 @@ #define REG2_LEDACT GENMASK(23, 22) #define REG2_LEDLINK GENMASK(25, 24) #define REG2_DIV4SEL BIT(27) +#define REG2_REVERSED BIT(28) #define REG2_ADCBYPASS BIT(30) #define REG2_CLKINSEL BIT(31) #define ETH_REG3 0x4 @@ -66,7 +67,7 @@ static int meson_gxl_enable_internal_mdio(struct mdio_mux_meson_gxl_priv *priv) * The only constraint is that it must match the one in * drivers/net/phy/meson-gxl.c to properly match the PHY. */ - writel(FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), + writel(REG2_REVERSED | FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), priv->regs + ETH_REG2); /* Enable the internal phy */ diff --git a/drivers/net/mtk_eth/mtk_eth.c b/drivers/net/mtk_eth/mtk_eth.c index b172838ba3a..a35754ccd1f 100644 --- a/drivers/net/mtk_eth/mtk_eth.c +++ b/drivers/net/mtk_eth/mtk_eth.c @@ -100,6 +100,7 @@ struct mtk_eth_priv { bool pn_swap; struct phy_device *phydev; + ofnode phy_node; int phy_interface; int phy_addr; @@ -572,6 +573,7 @@ static int mtk_phy_probe(struct udevice *dev) if (!phydev) return -ENODEV; + phydev->node = priv->phy_node; phydev->supported &= PHY_GBIT_FEATURES; phydev->advertising = phydev->supported; @@ -1458,6 +1460,8 @@ static int mtk_eth_of_to_plat(struct udevice *dev) return ret; } + priv->phy_node = args.node; + priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1); if (priv->phy_addr < 0) { printf("error: phy address is not specified\n"); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 21bf983056a..185c6a3156e 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -184,6 +184,8 @@ config PHY_MARVELL_10G help Support for the Marvell Alaska MV88X3310 and compatible PHYs. +source "drivers/net/phy/mediatek/Kconfig" + config PHY_MESON_GXL bool "Amlogic Meson GXL Internal PHY support" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index a119eb5e177..a339b8ac29d 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PHY_ET1011C) += et1011c.o obj-$(CONFIG_PHY_LXT) += lxt.o obj-$(CONFIG_PHY_MARVELL) += marvell.o obj-$(CONFIG_PHY_MARVELL_10G) += marvell10g.o +obj-y += mediatek/ obj-$(CONFIG_PHY_MICREL_KSZ8XXX) += micrel_ksz8xxx.o obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index be480ecef6c..dec024844b5 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -135,6 +135,7 @@ void cs4340_upload_firmware(struct phy_device *phydev) int i, line_cnt = 0, column_cnt = 0; struct cortina_reg_config fw_temp; char *addr = NULL; + char *to_be_freed = NULL; ulong cortina_fw_addr = (ulong)cs4340_get_fw_addr(); #ifdef CONFIG_TFABOOT @@ -147,6 +148,7 @@ void cs4340_upload_firmware(struct phy_device *phydev) size_t fw_length = CONFIG_CORTINA_FW_LENGTH; addr = malloc(CONFIG_CORTINA_FW_LENGTH); + to_be_freed = addr; ret = nand_read(get_nand_dev_by_index(0), (loff_t)cortina_fw_addr, &fw_length, (u_char *)addr); if (ret == -EUCLEAN) { @@ -158,6 +160,7 @@ void cs4340_upload_firmware(struct phy_device *phydev) struct spi_flash *ucode_flash; addr = malloc(CONFIG_CORTINA_FW_LENGTH); + to_be_freed = addr; ucode_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); if (!ucode_flash) { @@ -179,6 +182,7 @@ void cs4340_upload_firmware(struct phy_device *phydev) puts("Failed to find MMC device for Cortina ucode\n"); } else { addr = malloc(CONFIG_CORTINA_FW_LENGTH); + to_be_freed = addr; printf("MMC read: dev # %u, block # %u, count %u ...\n", dev, blk, cnt); mmc_init(mmc); @@ -199,6 +203,7 @@ void cs4340_upload_firmware(struct phy_device *phydev) size_t fw_length = CONFIG_CORTINA_FW_LENGTH; addr = malloc(CONFIG_CORTINA_FW_LENGTH); + to_be_freed = addr; ret = nand_read(get_nand_dev_by_index(0), (loff_t)cortina_fw_addr, &fw_length, (u_char *)addr); @@ -211,6 +216,7 @@ void cs4340_upload_firmware(struct phy_device *phydev) struct spi_flash *ucode_flash; addr = malloc(CONFIG_CORTINA_FW_LENGTH); + to_be_freed = addr; ucode_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); if (!ucode_flash) { @@ -232,6 +238,7 @@ void cs4340_upload_firmware(struct phy_device *phydev) puts("Failed to find MMC device for Cortina ucode\n"); } else { addr = malloc(CONFIG_CORTINA_FW_LENGTH); + to_be_freed = addr; printf("MMC read: dev # %u, block # %u, count %u ...\n", dev, blk, cnt); mmc_init(mmc); @@ -280,6 +287,8 @@ void cs4340_upload_firmware(struct phy_device *phydev) 0xffff; phy_write(phydev, 0x00, fw_temp.reg_addr, fw_temp.reg_value); } + if (to_be_freed) + free(to_be_freed); } #endif diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig new file mode 100644 index 00000000000..933271f01fa --- /dev/null +++ b/drivers/net/phy/mediatek/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config MTK_NET_PHYLIB + bool + +config PHY_MEDIATEK_2P5GE + bool "MediaTek built-in 2.5Gb ethernet PHYs" + depends on OF_CONTROL && (TARGET_MT7987 || TARGET_MT7988) + select FW_LOADER + select MTK_NET_PHYLIB + help + Supports MediaTek SoC built-in 2.5Gb ethernet PHYs. + + This driver requires firmware download for PHY to enable its + functionality. The board can override certian firmware downloading + function to provide the firmware data. diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile new file mode 100644 index 00000000000..bc8dd4e878c --- /dev/null +++ b/drivers/net/phy/mediatek/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o +obj-$(CONFIG_PHY_MEDIATEK_2P5GE) += mtk-2p5ge.o diff --git a/drivers/net/phy/mediatek/mtk-2p5ge.c b/drivers/net/phy/mediatek/mtk-2p5ge.c new file mode 100644 index 00000000000..4090db0b474 --- /dev/null +++ b/drivers/net/phy/mediatek/mtk-2p5ge.c @@ -0,0 +1,627 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 MediaTek Inc. All Rights Reserved. + * + * Author: Sky Huang <SkyLake.Huang@mediatek.com> + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/of_access.h> +#include <dm/pinctrl.h> +#include <dm/ofnode.h> +#include <fw_loader.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <phy.h> +#include "mtk.h" + +#define MTK_2P5GPHY_ID_MT7987 0x00339c91 +#define MTK_2P5GPHY_ID_MT7988 0x00339c11 + +#define PBUS_BASE 0x0f000000 +#define PBUS_SIZE 0x1f0024 + +#define MTK_2P5GPHY_PMD_REG 0x010000 +#define DO_NOT_RESET (MTK_2P5GPHY_PMD_REG + 0x28) +#define DO_NOT_RESET_XBZ BIT(0) +#define DO_NOT_RESET_PMA BIT(3) +#define DO_NOT_RESET_RX BIT(5) +#define FNPLL_PWR_CTRL1 (MTK_2P5GPHY_PMD_REG + 0x208) +#define RG_SPEED_MASK GENMASK(3, 0) +#define RG_SPEED_2500 BIT(3) +#define RG_SPEED_100 BIT(0) +#define FNPLL_PWR_CTRL_STATUS (MTK_2P5GPHY_PMD_REG + 0x20c) +#define RG_STABLE_MASK GENMASK(3, 0) +#define RG_SPEED_2500_STABLE BIT(3) +#define RG_SPEED_100_STABLE BIT(0) + +#define MTK_2P5GPHY_XBZ_PCS 0x030000 +#define PHY_CTRL_CONFIG (MTK_2P5GPHY_XBZ_PCS + 0x200) +#define PMU_WP (MTK_2P5GPHY_XBZ_PCS + 0x800) +#define WRITE_PROTECT_KEY 0xCAFEF00D +#define PMU_PMA_AUTO_CFG (MTK_2P5GPHY_XBZ_PCS + 0x820) +#define POWER_ON_AUTO_MODE BIT(16) +#define PMU_AUTO_MODE_EN BIT(0) +#define PMU_PMA_STATUS (MTK_2P5GPHY_XBZ_PCS + 0x840) +#define CLK_IS_DISABLED BIT(3) + +#define MTK_2P5GPHY_XBZ_PMA_RX 0x080000 +#define SMEM_WDAT0 (MTK_2P5GPHY_XBZ_PMA_RX + 0x5000) +#define SMEM_WDAT1 (MTK_2P5GPHY_XBZ_PMA_RX + 0x5004) +#define SMEM_WDAT2 (MTK_2P5GPHY_XBZ_PMA_RX + 0x5008) +#define SMEM_WDAT3 (MTK_2P5GPHY_XBZ_PMA_RX + 0x500c) +#define SMEM_CTRL (MTK_2P5GPHY_XBZ_PMA_RX + 0x5024) +#define SMEM_HW_RDATA_ZERO BIT(24) +#define SMEM_ADDR_REF_ADDR (MTK_2P5GPHY_XBZ_PMA_RX + 0x502c) +#define CM_CTRL_P01 (MTK_2P5GPHY_XBZ_PMA_RX + 0x5100) +#define CM_CTRL_P23 (MTK_2P5GPHY_XBZ_PMA_RX + 0x5124) +#define DM_CTRL_P01 (MTK_2P5GPHY_XBZ_PMA_RX + 0x5200) +#define DM_CTRL_P23 (MTK_2P5GPHY_XBZ_PMA_RX + 0x5224) + +#define MTK_2P5GPHY_CHIP_SCU 0x0cf800 +#define SYS_SW_RESET (MTK_2P5GPHY_CHIP_SCU + 0x128) +#define RESET_RST_CNT BIT(0) + +#define MTK_2P5GPHY_MCU_CSR 0x0f0000 +#define MD32_EN_CFG (MTK_2P5GPHY_MCU_CSR + 0x18) +#define MD32_EN BIT(0) + +#define MTK_2P5GPHY_PMB_FW 0x100000 + +#define MTK_2P5GPHY_FCM_BASE 0x0e0000 +#define FC_LWM (MTK_2P5GPHY_FCM_BASE + 0x14) +#define TX_FC_LWM_MASK GENMASK(31, 16) +#define MIN_IPG_NUM (MTK_2P5GPHY_FCM_BASE + 0x2c) +#define LS_MIN_IPG_NUM_MASK GENMASK(7, 0) +#define FIFO_CTRL (MTK_2P5GPHY_FCM_BASE + 0x40) +#define TX_SFIFO_IDLE_CNT_MASK GENMASK(31, 28) +#define TX_SFIFO_DEL_IPG_WM_MASK GENMASK(23, 16) + +#define MTK_2P5GPHY_APB_BASE 0x11c30000 +#define MTK_2P5GPHY_APB_SIZE 0x9c +#define SW_RESET 0x94 +#define MD32_RESTART_EN_CLEAR BIT(9) + +/* Registers on CL22 page 0 */ +#define PHY_AUX_CTRL_STATUS 0x1d +#define PHY_AUX_DPX_MASK GENMASK(5, 5) +#define PHY_AUX_SPEED_MASK GENMASK(4, 2) + +enum { + PHY_AUX_SPD_10 = 0, + PHY_AUX_SPD_100, + PHY_AUX_SPD_1000, + PHY_AUX_SPD_2500, +}; + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_LINK_STATUS_RELATED 0x147 +#define MTK_PHY_BYPASS_LINK_STATUS_OK BIT(4) +#define MTK_PHY_FORCE_LINK_STATUS_HCD BIT(3) + +#define MTK_PHY_AN_FORCE_SPEED_REG 0x313 +#define MTK_PHY_MASTER_FORCE_SPEED_SEL_EN BIT(7) +#define MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK GENMASK(6, 0) + +#define MTK_PHY_LPI_PCS_DSP_CTRL 0x121 +#define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8) + +#define MTK_PHY_PMA_PMD_SPEED_ABILITY 0x300 +#define CAP_100X_HDX BIT(14) +#define CAP_10T_HDX BIT(12) + +/* Registers on MDIO_MMD_VEND2 */ +#define MT7987_OPTIONS 0x110 +#define NORMAL_RETRAIN_DISABLE BIT(0) + +/* Registers on Token Ring debug nodes */ +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ +#define AUTO_NP_10XEN BIT(6) + +/* Firmware file size */ +#define MT7987_2P5GE_PMB_FW_SIZE 0x18000 +#define MT7988_2P5GE_PMB_FW_SIZE 0x20000 + +#define MT7987_2P5GE_DSPBITTB_SIZE 0x7000 + +struct mtk_i2p5ge_fw_info { + u8 datecode[4]; + u8 plat[2]; + u8 ver[2]; +}; + +struct mtk_i2p5ge_priv { + void __iomem *reg_base; +}; + +static inline void pbus_write(struct mtk_i2p5ge_priv *priv, u32 offset, + u32 val) +{ + writel(val, priv->reg_base + offset); +} + +static inline void pbus_rmw(struct mtk_i2p5ge_priv *priv, u32 offset, u32 clr, + u32 set) +{ + clrsetbits_le32(priv->reg_base + offset, clr, set); +} + +static int mt798x_i2p5ge_download_fw(struct mtk_i2p5ge_priv *priv, + size_t fwsize, const void *fwdata) +{ + u32 __iomem *fwmem = priv->reg_base + MTK_2P5GPHY_PMB_FW; + const u32 *fw; + u32 i; + + /* Assume fw data is 4-byte aligned */ + fw = fwdata; + + for (i = 0; i < (fwsize >> 2); i++) + writel(fw[i], &fwmem[i]); + + return 0; +} + +static int mt798x_i2p5ge_phy_probe(struct phy_device *phydev) +{ + struct mtk_i2p5ge_priv *priv; + + priv = malloc(sizeof(*priv)); + if (!priv) + return -ENOMEM; + + priv->reg_base = ioremap(PBUS_BASE, PBUS_SIZE); + if (!priv->reg_base) { + free(priv); + return -ENODEV; + } + + phydev->priv = priv; + + return 0; +} + +static int mt798x_i2p5ge_phy_config(struct phy_device *phydev) +{ + + /* Setup LED */ + phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_LINK10 | + MTK_PHY_LED_ON_LINK100 | + MTK_PHY_LED_ON_LINK1000 | + MTK_PHY_LED_ON_LINK2500); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, + MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX); + + /* Switch pinctrl after setting polarity to avoid bogus blinking */ + pinctrl_select_state(phydev->dev, "i2p5gbe-led"); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL, + MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0); + + /* Enable 16-bit next page exchange bit if 1000-BT isn't advertising */ + mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AUTO_NP_10XEN, + FIELD_PREP(AUTO_NP_10XEN, 0x1)); + + /* Set HW auto downshift */ + mtk_phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_1); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_AUX_CTRL_AND_STATUS, + MTK_PHY_ENABLE_DOWNSHIFT); + mtk_phy_restore_page(phydev); + + /* Configure parallel detction functionality */ + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_PMA_PMD_SPEED_ABILITY, + CAP_10T_HDX | CAP_100X_HDX); + phy_clear_bits_mmd(phydev, MDIO_DEVAD_NONE, + MII_ADVERTISE, + ADVERTISE_10HALF | ADVERTISE_100HALF); + + return 0; +} + +static void mt798x_i2p5ge_print_fw_info(const void *fwdata, size_t fwsize) +{ + const struct mtk_i2p5ge_fw_info *info; + u8 ver_minor, ver_patch; + + info = (const void *)((uintptr_t)fwdata + fwsize - sizeof(*info)); + + ver_minor = info->ver[1] >> 4; + ver_patch = info->ver[1] & 0xf; + + printf("Firmware loaded, date %02x%02x/%02x/%02x, ver %x.%u.%u\n", + info->datecode[0], info->datecode[1], info->datecode[2], + info->datecode[3], info->ver[0], ver_minor, ver_patch); +} + +int __weak mt7987_i2p5ge_get_fw(void **fw, size_t *fwsize, + void **dspfw, size_t *dspfwsize) +{ + void *pmb, *dsp; + int ret; + + pmb = malloc(MT7987_2P5GE_PMB_FW_SIZE); + if (!pmb) + return -ENOMEM; + + ret = request_firmware_into_buf_via_script( + pmb, MT7987_2P5GE_PMB_FW_SIZE, + "mt7987_i2p5ge_load_pmb_firmware", fwsize); + if (ret) { + free(pmb); + return ret; + } + + dsp = malloc(MT7987_2P5GE_DSPBITTB_SIZE); + if (!dsp) { + free(pmb); + return -ENOMEM; + } + + ret = request_firmware_into_buf_via_script( + dsp, MT7987_2P5GE_DSPBITTB_SIZE, + "mt7987_i2p5ge_load_dspbit_firmware", dspfwsize); + if (ret) { + free(pmb); + free(dsp); + return ret; + } + + *fw = pmb; + *dspfw = dsp; + + return 1; +} + +static int mt7987_i2p5ge_download_dspfw(struct mtk_i2p5ge_priv *priv, + const void *dspfw_data) +{ + const u32 *dspfw; + u32 i; + + pbus_rmw(priv, SMEM_CTRL, 0, SMEM_HW_RDATA_ZERO); + + pbus_rmw(priv, PHY_CTRL_CONFIG, 0, BIT(16)); + + /* Initialize data memory */ + pbus_rmw(priv, DM_CTRL_P01, 0, BIT(28)); + pbus_rmw(priv, DM_CTRL_P23, 0, BIT(28)); + + /* Initialize coefficient memory */ + pbus_rmw(priv, CM_CTRL_P01, 0, BIT(28)); + pbus_rmw(priv, CM_CTRL_P23, 0, BIT(28)); + + /* Initialize PM offset */ + pbus_write(priv, SMEM_ADDR_REF_ADDR, 0); + + /* Assume DSP bit data is 4-byte aligned */ + dspfw = dspfw_data; + + for (i = 0; i < (MT7987_2P5GE_DSPBITTB_SIZE >> 2); i += 4) { + pbus_write(priv, SMEM_WDAT0, dspfw[i]); + pbus_write(priv, SMEM_WDAT1, dspfw[i + 1]); + pbus_write(priv, SMEM_WDAT2, dspfw[i + 2]); + pbus_write(priv, SMEM_WDAT3, dspfw[i + 3]); + } + + pbus_rmw(priv, DM_CTRL_P01, BIT(28), 0); + pbus_rmw(priv, DM_CTRL_P23, BIT(28), 0); + + pbus_rmw(priv, CM_CTRL_P01, BIT(28), 0); + pbus_rmw(priv, CM_CTRL_P23, BIT(28), 0); + + return 0; +} + +static int mt7987_i2p5ge_phy_load_fw(struct phy_device *phydev) +{ + struct mtk_i2p5ge_priv *priv = phydev->priv; + size_t fw_size, dspfw_size; + void __iomem *apb_base; + void *fw, *dspfw; + int ret, fwrc; + u32 reg; + + apb_base = ioremap(MTK_2P5GPHY_APB_BASE, MTK_2P5GPHY_APB_SIZE); + if (!apb_base) + return -ENODEV; + + fwrc = mt7987_i2p5ge_get_fw(&fw, &fw_size, &dspfw, &dspfw_size); + if (fwrc < 0) { + dev_err(phydev->dev, "Failed to get firmware data\n"); + return -EINVAL; + } + + if (fw_size != MT7987_2P5GE_PMB_FW_SIZE) { + dev_err(phydev->dev, + "PMB firmware size mismatch (0x%zx != 0x%x)\n", + fw_size, MT7987_2P5GE_PMB_FW_SIZE); + ret = -EINVAL; + goto cleanup; + } + + if (dspfw_size != MT7987_2P5GE_DSPBITTB_SIZE) { + dev_err(phydev->dev, + "DSP code size mismatch (0x%zx != 0x%x)\n", + dspfw_size, MT7987_2P5GE_DSPBITTB_SIZE); + ret = -EINVAL; + goto cleanup; + } + + /* Force 2.5Gphy back to AN state */ + phy_set_bits_mmd(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + mdelay(5); + phy_set_bits_mmd(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_PDOWN); + + clrbits_le16(apb_base + SW_RESET, MD32_RESTART_EN_CLEAR); + setbits_le16(apb_base + SW_RESET, MD32_RESTART_EN_CLEAR); + clrbits_le16(apb_base + SW_RESET, MD32_RESTART_EN_CLEAR); + + pbus_rmw(priv, MD32_EN_CFG, MD32_EN, 0); + + ret = mt798x_i2p5ge_download_fw(priv, MT7987_2P5GE_PMB_FW_SIZE, fw); + if (ret) + goto cleanup; + + /* Enable 100Mbps module clock. */ + pbus_rmw(priv, FNPLL_PWR_CTRL1, RG_SPEED_MASK, RG_SPEED_100); + + /* Check if 100Mbps module clock is ready. */ + ret = readl_poll_timeout(priv->reg_base + FNPLL_PWR_CTRL_STATUS, reg, + reg & RG_SPEED_100_STABLE, 10000); + if (ret) { + dev_err(phydev->dev, + "Timed out enabling 100Mbps module clock\n"); + } + + /* Enable 2.5Gbps module clock. */ + pbus_rmw(priv, FNPLL_PWR_CTRL1, RG_SPEED_MASK, RG_SPEED_2500); + + /* Check if 2.5Gbps module clock is ready. */ + ret = readl_poll_timeout(priv->reg_base + FNPLL_PWR_CTRL_STATUS, reg, + reg & RG_SPEED_2500_STABLE, 10000); + + if (ret) { + dev_err(phydev->dev, + "Timed out enabling 2.5Gbps module clock\n"); + } + + /* Disable AN */ + phy_clear_bits_mmd(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_ANENABLE); + + /* Force to run at 2.5G speed */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_AN_FORCE_SPEED_REG, + MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK, + MTK_PHY_MASTER_FORCE_SPEED_SEL_EN | + FIELD_PREP(MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK, 0x1b)); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_RELATED, + MTK_PHY_BYPASS_LINK_STATUS_OK | + MTK_PHY_FORCE_LINK_STATUS_HCD); + + /* Set xbz, pma and rx as "do not reset" in order to input DSP code. */ + pbus_rmw(priv, DO_NOT_RESET, 0, + DO_NOT_RESET_XBZ | DO_NOT_RESET_PMA | DO_NOT_RESET_RX); + + pbus_rmw(priv, SYS_SW_RESET, RESET_RST_CNT, 0); + + pbus_write(priv, PMU_WP, WRITE_PROTECT_KEY); + + pbus_rmw(priv, PMU_PMA_AUTO_CFG, 0, + PMU_AUTO_MODE_EN | POWER_ON_AUTO_MODE); + + /* Check if clock in auto mode is disabled. */ + ret = readl_poll_timeout(priv->reg_base + PMU_PMA_STATUS, reg, + (reg & CLK_IS_DISABLED) == 0x0, 100000); + if (ret) + dev_err(phydev->dev, "Timed out enabling clock auto mode\n"); + + ret = mt7987_i2p5ge_download_dspfw(priv, dspfw); + if (ret) + goto cleanup; + + pbus_rmw(priv, MD32_EN_CFG, 0, MD32_EN); + + phy_set_bits_mmd(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + /* We need a delay here to stabilize initialization of MCU */ + mdelay(8); + + mt798x_i2p5ge_print_fw_info(fw, fw_size); + +cleanup: + if (fwrc > 0) { + free(fw); + free(dspfw); + } + + iounmap(apb_base); + + return ret; +} + +static int mt7987_i2p5ge_phy_config(struct phy_device *phydev) +{ + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_POLARITY); + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MT7987_OPTIONS, + NORMAL_RETRAIN_DISABLE); + + return mt798x_i2p5ge_phy_config(phydev); +} + +static int mt7987_i2p5ge_phy_probe(struct phy_device *phydev) +{ + int ret; + + ret = mt798x_i2p5ge_phy_probe(phydev); + if (ret) + return ret; + + return mt7987_i2p5ge_phy_load_fw(phydev); +} + +int __weak mt7988_i2p5ge_get_fw(void **fw, size_t *size) +{ + void *pmb; + int ret; + + pmb = malloc(MT7988_2P5GE_PMB_FW_SIZE); + if (!pmb) + return -ENOMEM; + + ret = request_firmware_into_buf_via_script( + pmb, MT7988_2P5GE_PMB_FW_SIZE, + "mt7988_i2p5ge_load_pmb_firmware", size); + if (ret) { + free(pmb); + return ret; + } + + *fw = pmb; + + return 1; +} + +static int mt7988_i2p5ge_phy_load_fw(struct phy_device *phydev) +{ + struct mtk_i2p5ge_priv *priv = phydev->priv; + size_t fw_size; + int ret, fwrc; + void *fw; + + fwrc = mt7988_i2p5ge_get_fw(&fw, &fw_size); + if (fwrc < 0) { + dev_err(phydev->dev, "Failed to get firmware data\n"); + return -EINVAL; + } + + if (fw_size != MT7988_2P5GE_PMB_FW_SIZE) { + dev_err(phydev->dev, "Firmware size mismatch (0x%zx != 0x%x)\n", + fw_size, MT7988_2P5GE_PMB_FW_SIZE); + ret = -EINVAL; + goto cleanup; + } + + ret = mt798x_i2p5ge_download_fw(priv, MT7988_2P5GE_PMB_FW_SIZE, fw); + if (ret) + goto cleanup; + + pbus_rmw(priv, MD32_EN_CFG, MD32_EN, 0); + pbus_rmw(priv, MD32_EN_CFG, 0, MD32_EN); + + phy_set_bits_mmd(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + /* We need a delay here to stabilize initialization of MCU */ + mdelay(8); + + mt798x_i2p5ge_print_fw_info(fw, fw_size); + +cleanup: + if (fwrc > 0) + free(fw); + + return ret; +} + +static int mt7988_i2p5ge_phy_config(struct phy_device *phydev) +{ + phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_POLARITY); + + return mt798x_i2p5ge_phy_config(phydev); +} + +static int mt7988_i2p5ge_phy_probe(struct phy_device *phydev) +{ + int ret; + + ret = mt798x_i2p5ge_phy_probe(phydev); + if (ret) + return ret; + + return mt7988_i2p5ge_phy_load_fw(phydev); +} + +static int mt798x_i2p5ge_phy_startup(struct phy_device *phydev) +{ + struct mtk_i2p5ge_priv *priv = phydev->priv; + int ret; + + ret = genphy_update_link(phydev); + if (ret) + return ret; + + /* Initialize speed/duplex */ + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + + if (phydev->link) { + ret = phy_read(phydev, MDIO_DEVAD_NONE, PHY_AUX_CTRL_STATUS); + if (ret < 0) + return ret; + + switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) { + case PHY_AUX_SPD_10: + phydev->speed = SPEED_10; + break; + + case PHY_AUX_SPD_100: + phydev->speed = SPEED_100; + break; + + case PHY_AUX_SPD_1000: + pbus_rmw(priv, FIFO_CTRL, + TX_SFIFO_IDLE_CNT_MASK | TX_SFIFO_DEL_IPG_WM_MASK, + FIELD_PREP(TX_SFIFO_IDLE_CNT_MASK, 0x1) | + FIELD_PREP(TX_SFIFO_DEL_IPG_WM_MASK, 0x10)); + pbus_rmw(priv, MIN_IPG_NUM, LS_MIN_IPG_NUM_MASK, + FIELD_PREP(LS_MIN_IPG_NUM_MASK, 0xa)); + pbus_rmw(priv, FC_LWM, TX_FC_LWM_MASK, + FIELD_PREP(TX_FC_LWM_MASK, 0x340)); + phydev->speed = SPEED_1000; + break; + + case PHY_AUX_SPD_2500: + phydev->speed = SPEED_2500; + break; + + default: + break; + } + + /* This PHY always operates in full duplex */ + phydev->duplex = DUPLEX_FULL; + } + + return 0; +} + +U_BOOT_PHY_DRIVER(mt7987_i2p5ge) = { + .name = "MediaTek MT7987 built-in 2.5GbE PHY", + .uid = MTK_2P5GPHY_ID_MT7987, + .mask = 0xfffffff0, + .features = PHY_10G_FEATURES, + .mmds = (MDIO_MMD_PCS | MDIO_MMD_AN | MDIO_MMD_VEND1 | MDIO_MMD_VEND2), + .probe = &mt7987_i2p5ge_phy_probe, + .config = &mt7987_i2p5ge_phy_config, + .startup = &mt798x_i2p5ge_phy_startup, + .shutdown = &genphy_shutdown, +}; + +U_BOOT_PHY_DRIVER(mt7988_i2p5ge) = { + .name = "MediaTek MT7988 built-in 2.5GbE PHY", + .uid = MTK_2P5GPHY_ID_MT7988, + .mask = 0xfffffff0, + .features = PHY_10G_FEATURES, + .mmds = (MDIO_MMD_PCS | MDIO_MMD_AN | MDIO_MMD_VEND1 | MDIO_MMD_VEND2), + .probe = &mt7988_i2p5ge_phy_probe, + .config = &mt7988_i2p5ge_phy_config, + .startup = &mt798x_i2p5ge_phy_startup, + .shutdown = &genphy_shutdown, +}; diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c new file mode 100644 index 00000000000..55e7a6b6eec --- /dev/null +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 MediaTek Inc. All Rights Reserved. + * + * Author: Sky Huang <SkyLake.Huang@mediatek.com> + */ +#include <dm/device_compat.h> +#include <phy.h> + +#include "mtk.h" + +void mtk_phy_select_page(struct phy_device *phydev, int page) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MTK_EXT_PAGE_ACCESS, page); +} + +void mtk_phy_restore_page(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MTK_EXT_PAGE_ACCESS, + MTK_PHY_PAGE_STANDARD); +} + +/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is + * mtk_tr* functions: wrapped by page switching operations + * __mtk_tr* functions: no page switching operations + */ +static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr, + u8 node_addr, u8 data_addr) +{ + u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */ + + if (read) + tr_cmd |= BIT(13); + + tr_cmd |= (((ch_addr & 0x3) << 11) | + ((node_addr & 0xf) << 7) | + ((data_addr & 0x3f) << 1)); + dev_dbg(phydev->dev, "tr_cmd: 0x%x\n", tr_cmd); + phy_write(phydev, MDIO_DEVAD_NONE, 0x10, tr_cmd); +} + +static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u16 *tr_high, u16 *tr_low) +{ + __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr); + *tr_low = phy_read(phydev, MDIO_DEVAD_NONE, 0x11); + *tr_high = phy_read(phydev, MDIO_DEVAD_NONE, 0x12); + dev_dbg(phydev->dev, "tr_high read: 0x%x, tr_low read: 0x%x\n", + *tr_high, *tr_low); +} + +u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr) +{ + u16 tr_high; + u16 tr_low; + + mtk_phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low); + mtk_phy_restore_page(phydev); + + return (tr_high << 16) | tr_low; +} + +static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 tr_data) +{ + phy_write(phydev, MDIO_DEVAD_NONE, 0x11, tr_data & 0xffff); + phy_write(phydev, MDIO_DEVAD_NONE, 0x12, tr_data >> 16); + dev_dbg(phydev->dev, "tr_high write: 0x%x, tr_low write: 0x%x\n", + tr_data >> 16, tr_data & 0xffff); + __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr); +} + +void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set) +{ + u32 tr_data; + u16 tr_high; + u16 tr_low; + + __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low); + tr_data = (tr_high << 16) | tr_low; + tr_data = (tr_data & ~mask) | set; + __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data); +} + +void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set) +{ + mtk_phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set); + mtk_phy_restore_page(phydev); +} + +void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 set) +{ + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set); +} + +void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 clr) +{ + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0); +} diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h new file mode 100644 index 00000000000..68044cbdb32 --- /dev/null +++ b/drivers/net/phy/mediatek/mtk.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 MediaTek Inc. All Rights Reserved. + * + * Author: Sky Huang <SkyLake.Huang@mediatek.com> + * + * Common definition for Mediatek Ethernet PHYs + */ + +#ifndef _MTK_EPHY_H_ +#define _MTK_EPHY_H_ + +#define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED_1 0x0001 +#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 +/* suprv_media_select_RefClk */ +#define MTK_PHY_LP_DETECTED_MASK GENMASK(7, 6) +#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) + +#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +/* Registers on Token Ring debug nodes */ +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x2 */ +#define AN_STATE_MASK GENMASK(22, 19) +#define AN_STATE_SHIFT 19 +#define AN_STATE_TX_DISABLE 1 + +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ +#define AN_NEW_LP_CNT_LIMIT_MASK GENMASK(23, 20) +#define AUTO_NP_10XEN BIT(6) + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_LINK_STATUS_MISC (0xa2) +#define MTK_PHY_FINAL_SPEED_1000 BIT(3) + +/* Registers on MDIO_MMD_VEND2 */ +#define MTK_PHY_LED0_ON_CTRL 0x24 +#define MTK_PHY_LED1_ON_CTRL 0x26 +#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0) +#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0) +#define MTK_PHY_LED_ON_LINK1000 BIT(0) +#define MTK_PHY_LED_ON_LINK100 BIT(1) +#define MTK_PHY_LED_ON_LINK10 BIT(2) +#define MTK_PHY_LED_ON_LINKDOWN BIT(3) +#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ +#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ +#define MTK_PHY_LED_ON_FORCE_ON BIT(6) +#define MTK_PHY_LED_ON_LINK2500 BIT(7) +#define MTK_PHY_LED_ON_POLARITY BIT(14) +#define MTK_PHY_LED_ON_ENABLE BIT(15) + +#define MTK_PHY_LED0_BLINK_CTRL 0x25 +#define MTK_PHY_LED1_BLINK_CTRL 0x27 +#define MTK_PHY_LED_BLINK_1000TX BIT(0) +#define MTK_PHY_LED_BLINK_1000RX BIT(1) +#define MTK_PHY_LED_BLINK_100TX BIT(2) +#define MTK_PHY_LED_BLINK_100RX BIT(3) +#define MTK_PHY_LED_BLINK_10TX BIT(4) +#define MTK_PHY_LED_BLINK_10RX BIT(5) +#define MTK_PHY_LED_BLINK_COLLISION BIT(6) +#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) +#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) +#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) +#define MTK_PHY_LED_BLINK_2500TX BIT(10) +#define MTK_PHY_LED_BLINK_2500RX BIT(11) + +#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \ + MTK_PHY_LED_ON_LINK100 | \ + MTK_PHY_LED_ON_LINK10) +#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) +#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) + +#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \ + MTK_GPHY_LED_ON_SET) +#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_RX_BLINK_SET) +#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_TX_BLINK_SET) + +#define MTK_PHY_LED_STATE_FORCE_ON 0 +#define MTK_PHY_LED_STATE_FORCE_BLINK 1 +#define MTK_PHY_LED_STATE_NETDEV 2 + +void mtk_phy_select_page(struct phy_device *phydev, int page); +void mtk_phy_restore_page(struct phy_device *phydev); + +u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr); +void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); +void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); +void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 set); +void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 clr); + +#endif /* _MTK_EPHY_H_ */ diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig index 52267339de0..93c3a0c35f2 100644 --- a/drivers/net/ti/Kconfig +++ b/drivers/net/ti/Kconfig @@ -49,6 +49,7 @@ config TI_AM65_CPSW_NUSS imply MISC imply SYSCON imply MDIO_TI_CPSW + imply SPL_SYSCON select PHYLIB help This driver supports TI K3 MCU CPSW Nuss Ethernet controller diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 9b69f36d04d..7a88f76fd09 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -234,14 +234,11 @@ out: #define AM65_GMII_SEL_MODE_RGMII 2 #define AM65_GMII_SEL_MODE_SGMII 3 -#define AM65_GMII_SEL_RGMII_IDMODE BIT(4) - static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, phy_interface_t phy_mode) { struct udevice *dev = priv->dev; u32 offset, reg, phandle; - bool rgmii_id = false; fdt_addr_t gmii_sel; u32 mode = 0; ofnode node; @@ -278,12 +275,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, mode = AM65_GMII_SEL_MODE_RGMII; break; - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - mode = AM65_GMII_SEL_MODE_RGMII; - rgmii_id = true; - break; - case PHY_INTERFACE_MODE_SGMII: mode = AM65_GMII_SEL_MODE_SGMII; break; @@ -298,9 +289,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, break; }; - if (rgmii_id) - mode |= AM65_GMII_SEL_RGMII_IDMODE; - reg = mode; dev_dbg(dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n", phy_mode, reg); @@ -628,9 +616,9 @@ static int am65_cpsw_phy_init(struct udevice *dev) struct eth_pdata *pdata = dev_get_plat(dev); struct phy_device *phydev; u32 supported = PHY_GBIT_FEATURES; - int ret; + int ret = 0; - phydev = dm_eth_phy_connect(dev); + phydev = dm_eth_phy_connect_interface(dev, pdata->phy_interface); if (!phydev) { dev_err(dev, "phy_connect() failed\n"); return -ENODEV; @@ -657,9 +645,28 @@ static int am65_cpsw_ofdata_parse_phy(struct udevice *dev) dev_read_u32(dev, "reg", &priv->port_id); pdata->phy_interface = dev_read_phy_mode(dev); - if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { + + /* CPSW controllers supported by this driver have a fixed internal TX + * delay in RGMII mode. Fix up PHY mode to account for this and warn + * about Device Trees that claim to have a TX delay on the PCB. + */ + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_RGMII_ID: + pdata->phy_interface = PHY_INTERFACE_MODE_RGMII_RXID; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + pdata->phy_interface = PHY_INTERFACE_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_RXID: + dev_warn(dev, + "RGMII mode without internal TX delay unsupported; please fix your Device Tree\n"); + break; + case PHY_INTERFACE_MODE_NA: dev_err(dev, "Invalid PHY mode, port %u\n", priv->port_id); return -EINVAL; + default: + break; } dev_read_u32(dev, "max-speed", (u32 *)&pdata->max_speed); @@ -705,7 +712,6 @@ static int am65_cpsw_probe_nuss(struct udevice *dev) struct am65_cpsw_common *cpsw_common = dev_get_priv(dev); ofnode ports_np, node; int ret, i; - struct udevice *port_dev; cpsw_common->dev = dev; cpsw_common->ss_base = dev_read_addr(dev); @@ -732,6 +738,7 @@ static int am65_cpsw_probe_nuss(struct udevice *dev) ports_np = dev_read_subnode(dev, "ethernet-ports"); if (!ofnode_valid(ports_np)) { ret = -ENOENT; + dev_err(dev, "Invalid device tree node %d\n", ret); goto out; } @@ -763,12 +770,6 @@ static int am65_cpsw_probe_nuss(struct udevice *dev) continue; cpsw_common->ports[port_id].disabled = disabled; - if (disabled) - continue; - - ret = device_bind_driver_to_node(dev, "am65_cpsw_nuss_port", ofnode_get_name(node), node, &port_dev); - if (ret) - dev_err(dev, "Failed to bind to %s node\n", ofnode_get_name(node)); } for (i = 0; i < AM65_CPSW_CPSWNU_MAX_PORTS; i++) { @@ -798,6 +799,37 @@ out: return ret; } +static int am65_cpsw_nuss_bind(struct udevice *dev) +{ + struct uclass_driver *drv; + struct udevice *port_dev; + ofnode ports_np, node; + int ret; + + drv = lists_uclass_lookup(UCLASS_ETH); + if (!drv) { + puts("Cannot find eth driver"); + return -ENOENT; + } + + ports_np = dev_read_subnode(dev, "ethernet-ports"); + if (!ofnode_valid(ports_np)) + return -ENOENT; + + ofnode_for_each_subnode(node, ports_np) { + const char *node_name; + + node_name = ofnode_get_name(node); + + ret = device_bind_driver_to_node(dev, "am65_cpsw_nuss_port", node_name, node, + &port_dev); + if (ret) + dev_err(dev, "Failed to bind to %s node\n", node_name); + } + + return ret; +} + static const struct udevice_id am65_cpsw_nuss_ids[] = { { .compatible = "ti,am654-cpsw-nuss" }, { .compatible = "ti,j721e-cpsw-nuss" }, @@ -809,6 +841,7 @@ U_BOOT_DRIVER(am65_cpsw_nuss) = { .name = "am65_cpsw_nuss", .id = UCLASS_MISC, .of_match = am65_cpsw_nuss_ids, + .bind = am65_cpsw_nuss_bind, .probe = am65_cpsw_probe_nuss, .priv_auto = sizeof(struct am65_cpsw_common), }; diff --git a/drivers/net/ti/icssg_prueth.c b/drivers/net/ti/icssg_prueth.c index d8df3c9afb0..12a162b9d68 100644 --- a/drivers/net/ti/icssg_prueth.c +++ b/drivers/net/ti/icssg_prueth.c @@ -647,8 +647,6 @@ static int prueth_probe(struct udevice *dev) return -EINVAL; } - if (port_id < 0) - continue; if (disabled) continue; diff --git a/drivers/nvme/Kconfig b/drivers/nvme/Kconfig index d138867666b..b69fc4ed53d 100644 --- a/drivers/nvme/Kconfig +++ b/drivers/nvme/Kconfig @@ -11,6 +11,7 @@ config NVME config NVME_APPLE bool "Apple NVMe controller support" + depends on ARCH_APPLE select NVME help This option enables support for the NVMe storage diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8ffd88c722d..ea9868425d0 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -183,6 +183,7 @@ config SYS_FSL_PCI_VER_3_X config PCIE_FSL bool "FSL PowerPC PCIe support" select SYS_FSL_PCI_VER_3_X if ARCH_T2080 || ARCH_T4240 + depends on PPC help Say Y here if you want to enable PCIe controller support on FSL PowerPC MPC85xx, MPC86xx, B series, P series and T series SoCs. @@ -190,6 +191,7 @@ config PCIE_FSL config PCI_MPC85XX bool "MPC85XX PowerPC PCI support" + depends on MPC85xx help Say Y here if you want to enable PCI controller support on FSL PowerPC MPC85xx SoC. @@ -265,6 +267,7 @@ config PCIE_LAYERSCAPE config PCIE_LAYERSCAPE_RC bool "Layerscape PCIe Root Complex mode support" + depends on ARM select PCIE_LAYERSCAPE help Enable Layerscape PCIe Root Complex mode driver support. The Layerscape @@ -286,6 +289,7 @@ config PCI_IOMMU_EXTRA_MAPPINGS config PCIE_LAYERSCAPE_EP bool "Layerscape PCIe Endpoint mode support" + depends on ARM select PCIE_LAYERSCAPE select PCI_ENDPOINT help @@ -296,6 +300,7 @@ config PCIE_LAYERSCAPE_EP config PCIE_LAYERSCAPE_GEN4 bool "Layerscape Gen4 PCIe support" + depends on ARM help Support PCIe Gen4 on NXP Layerscape SoCs, which may have one or several PCIe controllers. The PCIe controller can work in RC or @@ -328,12 +333,6 @@ config PCIE_IMX bool "i.MX PCIe support" depends on ARCH_MX6 -config PCIE_INTEL_FPGA - bool "Intel FPGA PCIe support" - help - Say Y here if you want to enable PCIe controller support on Intel - FPGA, example Stratix 10. - config PCIE_IPROC bool "Iproc PCIe support" help @@ -456,7 +455,7 @@ config PCIE_STARFIVE_JH7110 config PCIE_DW_IMX bool "i.MX DW PCIe controller support" - depends on ARCH_IMX8M + depends on ARCH_IMX8M || ARCH_IMX9 select PCIE_DW_COMMON select DM_REGULATOR select REGMAP diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index a0420e733ed..98f3c226f63 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_fixup_common.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o -obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o diff --git a/drivers/pci/pcie_apple.c b/drivers/pci/pcie_apple.c index 6a8e715d4b6..f5fda9835dc 100644 --- a/drivers/pci/pcie_apple.c +++ b/drivers/pci/pcie_apple.c @@ -246,8 +246,9 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np) { struct apple_pcie_port *port; struct gpio_desc reset; + struct fdt_pci_addr pci_addr; fdt_addr_t addr; - u32 stat, idx; + u32 stat; int ret; char name[16]; @@ -259,12 +260,13 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np) if (!port) return -ENOMEM; - ret = ofnode_read_u32_index(np, "reg", 0, &idx); + ret = ofnode_read_pci_addr(np, FDT_PCI_SPACE_CONFIG, "reg", + &pci_addr, NULL); if (ret) return ret; /* Use the first reg entry to work out the port index */ - port->idx = idx >> 11; + port->idx = PCI_DEV(pci_addr.phys_hi); port->pcie = pcie; port->reset = reset; port->np = np; @@ -333,9 +335,10 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np) static int apple_pcie_probe(struct udevice *dev) { struct apple_pcie_priv *pcie = dev_get_priv(dev); + struct fdt_pci_addr pci_addr; fdt_addr_t addr; ofnode of_port; - int i, ret; + int ret; pcie->hw = (struct reg_info *)dev_get_driver_data(dev); @@ -357,9 +360,14 @@ static int apple_pcie_probe(struct udevice *dev) of_port = ofnode_next_subnode(of_port)) { if (!ofnode_is_enabled(of_port)) continue; + ret = ofnode_read_pci_addr(of_port, FDT_PCI_SPACE_CONFIG, + "reg", &pci_addr, NULL); + if (ret) + continue; ret = apple_pcie_setup_port(pcie, of_port); if (ret) { - dev_err(pcie->dev, "Port %d setup fail: %d\n", i, ret); + dev_err(pcie->dev, "Port %d setup fail: %d\n", + PCI_DEV(pci_addr.phys_hi), ret); return ret; } } diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c index c4cad019373..4113a9f03cf 100644 --- a/drivers/pci/pcie_dw_common.c +++ b/drivers/pci/pcie_dw_common.c @@ -7,7 +7,6 @@ * * Copyright (C) 2018 Texas Instruments, Inc */ - #include <dm.h> #include <log.h> #include <pci.h> @@ -385,7 +384,7 @@ void pcie_dw_setup_host(struct pcie_dw *pci) 0xffffff, 0x00ff0100); /* setup command register */ - clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS, + clrsetbits_le32(pci->dbi_base + PCI_COMMAND, 0xffff, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR); diff --git a/drivers/pci/pcie_dw_imx.c b/drivers/pci/pcie_dw_imx.c index fdb463710ba..41d9f3c20b9 100644 --- a/drivers/pci/pcie_dw_imx.c +++ b/drivers/pci/pcie_dw_imx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2024 Linaro Ltd. + * Copyright 2025 NXP * * Author: Sumit Garg <sumit.garg@linaro.org> */ @@ -45,6 +46,47 @@ #define IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10) #define IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11) +#define IMX95_PCIE_PHY_GEN_CTRL 0x0 +#define IMX95_PCIE_REF_USE_PAD BIT(17) + +#define IMX95_PCIE_PHY_MPLLA_CTRL 0x10 +#define IMX95_PCIE_PHY_MPLL_STATE BIT(30) + +#define IMX95_PCIE_SS_RW_REG_0 0xf0 +#define IMX95_PCIE_REF_CLKEN BIT(23) +#define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) +#define IMX95_PCIE_SS_RW_REG_1 0xf4 +#define IMX95_PCIE_CLKREQ_OVERRIDE_EN BIT(8) +#define IMX95_PCIE_CLKREQ_OVERRIDE_VAL BIT(9) +#define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31) + +#define IMX95_PE0_GEN_CTRL_1 0x1050 +#define IMX95_PCIE_DEVICE_TYPE GENMASK(3, 0) + +#define IMX95_PE0_GEN_CTRL_3 0x1058 +#define IMX95_PCIE_LTSSM_EN BIT(0) + +#define IMX95_PCIE_RST_CTRL 0x3010 +#define IMX95_PCIE_COLD_RST BIT(0) + +#define GEN3_RELATED_OFF 0x890 +#define GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL BIT(0) +#define GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS BIT(13) +#define GEN3_RELATED_OFF_GEN3_EQ_DISABLE BIT(16) +#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT 24 +#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK GENMASK(25, 24) +#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_16_0GT 0x1 + +#define IMX_PCIE_FLAG_HAS_PHYDRV BIT(3) +#define IMX_PCIE_FLAG_HAS_APP_RESET BIT(4) +#define IMX_PCIE_FLAG_HAS_SERDES BIT(6) + +#define IMX_PCIE_MAX_INSTANCES 2 + +/* Parameters for the waiting for PCIe PHY PLL to lock s*/ +#define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 +#define PHY_PLL_LOCK_WAIT_TIMEOUT (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX / 1000) + struct pcie_dw_imx { /* Must be first member of the struct */ struct pcie_dw dw; @@ -54,20 +96,196 @@ struct pcie_dw_imx { struct reset_ctl apps_reset; struct phy phy; struct udevice *vpcie; + void *info; + u32 max_link_speed; + bool enable_ext_refclk; + bool supports_clkreq; }; struct pcie_chip_info { + u32 flags; + const u32 ltssm_off; + const u32 ltssm_mask; + const u32 mode_off[IMX_PCIE_MAX_INSTANCES]; + const u32 mode_mask[IMX_PCIE_MAX_INSTANCES]; const char *gpr; + void (*init_phy)(struct pcie_dw_imx *priv); + int (*enable_ref_clk)(struct pcie_dw_imx *priv, bool enable); + int (*core_reset)(struct pcie_dw_imx *priv, bool assert); + int (*wait_pll_lock)(struct pcie_dw_imx *priv); + void (*post_config)(struct pcie_dw_imx *priv); }; +static void imx95_pcie_init_phy(struct pcie_dw_imx *priv) +{ +/* + * Workaround for ERR051624: The Controller Without Vaux Cannot + * Exit L23 Ready Through Beacon or PERST# De-assertion + * + * When the auxiliary power is not available the controller + * cannot exit from L23 Ready with beacon or PERST# de-assertion + * when main power is not removed. + * + * Workaround: Set SS_RW_REG_1[SYS_AUX_PWR_DET] to 1. + */ + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_SYS_AUX_PWR_DET, + IMX95_PCIE_SYS_AUX_PWR_DET); + + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, + IMX95_PCIE_PHY_CR_PARA_SEL, + IMX95_PCIE_PHY_CR_PARA_SEL); + + if (priv->enable_ext_refclk) { + /* External clock is used as reference clock */ + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL, + IMX95_PCIE_REF_USE_PAD, + IMX95_PCIE_REF_USE_PAD); + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, + IMX95_PCIE_REF_CLKEN, 0); + } else { + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL, + IMX95_PCIE_REF_USE_PAD, 0); + + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, + IMX95_PCIE_REF_CLKEN, IMX95_PCIE_REF_CLKEN); + } + + /* Force CLKREQ# low by override */ + if (!priv->supports_clkreq) + regmap_update_bits(priv->iomuxc_gpr, + IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_CLKREQ_OVERRIDE_EN | + IMX95_PCIE_CLKREQ_OVERRIDE_VAL, + IMX95_PCIE_CLKREQ_OVERRIDE_EN | + IMX95_PCIE_CLKREQ_OVERRIDE_VAL); +} + +static int imx95_pcie_wait_for_phy_pll_lock(struct pcie_dw_imx *priv) +{ + u32 val; + + if (regmap_read_poll_timeout(priv->iomuxc_gpr, + IMX95_PCIE_PHY_MPLLA_CTRL, val, + val & IMX95_PCIE_PHY_MPLL_STATE, + PHY_PLL_LOCK_WAIT_USLEEP_MAX, + PHY_PLL_LOCK_WAIT_TIMEOUT)) { + printf("PCIe PLL lock timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int imx95_pcie_core_reset(struct pcie_dw_imx *priv, bool assert) +{ + u32 val; + + if (assert) { + /* + * From i.MX95 PCIe PHY perspective, the COLD reset toggle + * should be complete after power-up by the following sequence. + * > 10us(at power-up) + * > 10ns(warm reset) + * |<------------>| + * ______________ + * phy_reset ____/ \________________ + * ____________ + * ref_clk_en_______________________/ + * Toggle COLD reset aligned with this sequence for i.MX95 PCIe. + */ + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST, IMX95_PCIE_COLD_RST); + /* + * Make sure the write to IMX95_PCIE_RST_CTRL is flushed to the + * hardware by doing a read. Otherwise, there is no guarantee + * that the write has reached the hardware before udelay(). + */ + regmap_read(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, &val); + udelay(15); + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST, 0); + regmap_read(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, &val); + udelay(10); + } + + return 0; +} + +static void imx95_pcie_post_config(struct pcie_dw_imx *priv) +{ + u32 val; + + /* + * Workaround for ERR051586: Compliance with 8GT/s Receiver + * Impedance ECN + * + * The default value of GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] is + * 1 which makes receiver non-compliant with the ZRX-DC + * parameter for 2.5 GT/s when operating at 8 GT/s or higher. It + * causes unnecessary timeout in L1. + * + * Workaround: Program GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] to 0. + */ + dw_pcie_dbi_write_enable(&priv->dw, true); + val = readl(priv->dw.dbi_base + GEN3_RELATED_OFF); + val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; + writel(val, priv->dw.dbi_base + GEN3_RELATED_OFF); + dw_pcie_dbi_write_enable(&priv->dw, false); +} + +static int imx8mm_pcie_enable_ref_clk(struct pcie_dw_imx *priv, bool enable) +{ + regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, + IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE, + enable ? 0 : IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE); + regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, + IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN, + enable ? IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0); + return 0; +} + static const struct pcie_chip_info imx8mm_chip_info = { + .flags = IMX_PCIE_FLAG_HAS_APP_RESET | IMX_PCIE_FLAG_HAS_PHYDRV, .gpr = "fsl,imx8mm-iomuxc-gpr", + .enable_ref_clk = imx8mm_pcie_enable_ref_clk, }; static const struct pcie_chip_info imx8mp_chip_info = { + .flags = IMX_PCIE_FLAG_HAS_APP_RESET | IMX_PCIE_FLAG_HAS_PHYDRV, .gpr = "fsl,imx8mp-iomuxc-gpr", + .enable_ref_clk = imx8mm_pcie_enable_ref_clk, +}; + +static const struct pcie_chip_info imx95_chip_info = { + .flags = IMX_PCIE_FLAG_HAS_SERDES, + .ltssm_off = IMX95_PE0_GEN_CTRL_3, + .ltssm_mask = IMX95_PCIE_LTSSM_EN, + .mode_off[0] = IMX95_PE0_GEN_CTRL_1, + .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, + .init_phy = imx95_pcie_init_phy, + .core_reset = imx95_pcie_core_reset, + .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, + .post_config = imx95_pcie_post_config, }; +static void imx_pcie_configure_type(struct pcie_dw_imx *priv) +{ + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + unsigned int mask, val, mode; + + mode = PCI_EXP_TYPE_ROOT_PORT; + + /* If mode_mask is 0, then generic PHY driver is used to set the mode */ + if (!info->mode_mask[0]) + return; + + mask = info->mode_mask[0]; + val = mode << (ffs(mask) - 1); + + regmap_update_bits(priv->iomuxc_gpr, info->mode_off[0], mask, val); +} + static void pcie_dw_configure(struct pcie_dw_imx *priv, u32 cap_speed) { dw_pcie_dbi_write_enable(&priv->dw, true); @@ -75,17 +293,34 @@ static void pcie_dw_configure(struct pcie_dw_imx *priv, u32 cap_speed) clrsetbits_le32(priv->dw.dbi_base + PCIE_LINK_CAPABILITY, TARGET_LINK_SPEED_MASK, cap_speed); + clrsetbits_le32(priv->dw.dbi_base + PCIE_LINK_CTL_2, + TARGET_LINK_SPEED_MASK, cap_speed); + dw_pcie_dbi_write_enable(&priv->dw, false); } static void imx_pcie_ltssm_enable(struct pcie_dw_imx *priv) { - reset_deassert(&priv->apps_reset); + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->ltssm_mask) + regmap_update_bits(priv->iomuxc_gpr, info->ltssm_off, info->ltssm_mask, + info->ltssm_mask); + + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_deassert(&priv->apps_reset); } static void imx_pcie_ltssm_disable(struct pcie_dw_imx *priv) { - reset_assert(&priv->apps_reset); + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->ltssm_mask) + regmap_update_bits(priv->iomuxc_gpr, info->ltssm_off, + info->ltssm_mask, 0); + + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_assert(&priv->apps_reset); } static bool is_link_up(u32 val) @@ -122,6 +357,11 @@ static int pcie_link_up(struct pcie_dw_imx *priv, u32 cap_speed) static int imx_pcie_assert_core_reset(struct pcie_dw_imx *priv) { + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->core_reset) + info->core_reset(priv, true); + if (dm_gpio_is_valid(&priv->reset_gpio)) { dm_gpio_set_value(&priv->reset_gpio, 1); mdelay(20); @@ -133,6 +373,7 @@ static int imx_pcie_assert_core_reset(struct pcie_dw_imx *priv) static int imx_pcie_clk_enable(struct pcie_dw_imx *priv) { int ret; + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); ret = clk_enable_bulk(&priv->clks); if (ret) @@ -142,11 +383,8 @@ static int imx_pcie_clk_enable(struct pcie_dw_imx *priv) * Set the over ride low and enabled make sure that * REF_CLK is turned on. */ - regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, - IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE, 0); - regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, - IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN, - IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN); + if (info->enable_ref_clk) + info->enable_ref_clk(priv, true); /* allow the clocks to stabilize */ udelay(500); @@ -156,6 +394,11 @@ static int imx_pcie_clk_enable(struct pcie_dw_imx *priv) static void imx_pcie_deassert_core_reset(struct pcie_dw_imx *priv) { + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->core_reset) + info->core_reset(priv, false); + if (!dm_gpio_is_valid(&priv->reset_gpio)) return; @@ -170,10 +413,11 @@ static int pcie_dw_imx_probe(struct udevice *dev) struct pcie_dw_imx *priv = dev_get_priv(dev); struct udevice *ctlr = pci_get_controller(dev); struct pci_controller *hose = dev_get_uclass_priv(ctlr); + struct pcie_chip_info *info = (void *)dev_get_driver_data(dev); int ret; if (priv->vpcie) { - ret = regulator_set_enable(priv->vpcie, true); + ret = regulator_set_enable_if_allowed(priv->vpcie, true); if (ret) { dev_err(dev, "failed to enable vpcie regulator\n"); return ret; @@ -186,31 +430,49 @@ static int pcie_dw_imx_probe(struct udevice *dev) return ret; } + if (info->init_phy) + info->init_phy(priv); + + imx_pcie_configure_type(priv); + ret = imx_pcie_clk_enable(priv); if (ret) { dev_err(dev, "failed to enable clocks\n"); goto err_clk; } - ret = generic_phy_init(&priv->phy); - if (ret) { - dev_err(dev, "failed to initialize PHY\n"); - goto err_phy_init; - } + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) { + ret = generic_phy_init(&priv->phy); + if (ret) { + dev_err(dev, "failed to initialize PHY\n"); + goto err_phy_init; + } - ret = generic_phy_power_on(&priv->phy); - if (ret) { - dev_err(dev, "failed to power on PHY\n"); - goto err_phy_power; + ret = generic_phy_power_on(&priv->phy); + if (ret) { + dev_err(dev, "failed to power on PHY\n"); + goto err_phy_power; + } } imx_pcie_deassert_core_reset(priv); + if (info->wait_pll_lock) { + ret = info->wait_pll_lock(priv); + if (ret) { + dev_err(dev, "failed to wait pll lock\n"); + goto err_link; + } + } + + if (info->post_config) + info->post_config(priv); + priv->dw.first_busno = dev_seq(dev); priv->dw.dev = dev; pcie_dw_setup_host(&priv->dw); - if (pcie_link_up(priv, LINK_SPEED_GEN_1)) { + if (pcie_link_up(priv, priv->max_link_speed)) { printf("PCIE-%d: Link down\n", dev_seq(dev)); ret = -ENODEV; goto err_link; @@ -229,26 +491,41 @@ static int pcie_dw_imx_probe(struct udevice *dev) return 0; err_link: - generic_shutdown_phy(&priv->phy); + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) + generic_shutdown_phy(&priv->phy); err_phy_power: - generic_phy_exit(&priv->phy); + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) + generic_phy_exit(&priv->phy); err_phy_init: - clk_disable_bulk(&priv->clks); + clk_release_bulk(&priv->clks); err_clk: imx_pcie_deassert_core_reset(priv); + dm_gpio_free(dev, &priv->reset_gpio); + + if (priv->vpcie) + regulator_set_enable_if_allowed(priv->vpcie, false); + return ret; } static int pcie_dw_imx_remove(struct udevice *dev) { struct pcie_dw_imx *priv = dev_get_priv(dev); + struct pcie_chip_info *info = (void *)dev_get_driver_data(dev); + + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) + generic_shutdown_phy(&priv->phy); - generic_shutdown_phy(&priv->phy); dm_gpio_free(dev, &priv->reset_gpio); - reset_free(&priv->apps_reset); + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_free(&priv->apps_reset); + clk_release_bulk(&priv->clks); + if (priv->vpcie) + regulator_set_enable_if_allowed(priv->vpcie, false); + return 0; } @@ -257,7 +534,9 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) struct pcie_chip_info *info = (void *)dev_get_driver_data(dev); struct pcie_dw_imx *priv = dev_get_priv(dev); ofnode gpr; - int ret; + int ret, index; + + priv->info = info; /* Get the controller base address */ priv->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbi"); @@ -274,17 +553,29 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) return -EINVAL; } + priv->dw.atu_base = (void *)dev_read_addr_name_ptr(dev, "atu"); + if (!priv->dw.atu_base) + dev_dbg(dev, "failed to get atu address from dtb\n"); + ret = clk_get_bulk(dev, &priv->clks); if (ret) { dev_err(dev, "failed to get PCIe clks\n"); return ret; } - ret = reset_get_by_name(dev, "apps", &priv->apps_reset); - if (ret) { - dev_err(dev, - "Failed to get PCIe apps reset control\n"); - goto err_reset; + index = ofnode_stringlist_search(dev_ofnode(dev), "clock-names", "ext-ref"); + if (index < 0) + priv->enable_ext_refclk = false; + else + priv->enable_ext_refclk = true; + + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) { + ret = reset_get_by_name(dev, "apps", &priv->apps_reset); + if (ret) { + dev_err(dev, + "Failed to get PCIe apps reset control\n"); + goto err_reset; + } } ret = gpio_request_by_name(dev, "reset-gpio", 0, &priv->reset_gpio, @@ -294,26 +585,58 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) goto err_gpio; } - ret = generic_phy_get_by_name(dev, "pcie-phy", &priv->phy); - if (ret) { - dev_err(dev, "failed to get pcie phy\n"); - goto err_phy; + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) { + ret = generic_phy_get_by_name(dev, "pcie-phy", &priv->phy); + if (ret) { + dev_err(dev, "failed to get pcie phy\n"); + goto err_phy; + } } - gpr = ofnode_by_compatible(ofnode_null(), info->gpr); - if (ofnode_equal(gpr, ofnode_null())) { - dev_err(dev, "unable to find GPR node\n"); - ret = -ENODEV; - goto err_phy; + if (info->flags & IMX_PCIE_FLAG_HAS_SERDES) { + void __iomem *app_base; + fdt_size_t app_size; + struct regmap_config config; + + app_base = (void *)dev_read_addr_size_name(dev, "app", &app_size); + if ((fdt_addr_t)app_base == FDT_ADDR_T_NONE) { + dev_err(dev, "failed to get app_base address\n"); + return -EINVAL; + } + + config.r_start = (ulong)app_base; + config.r_size = (ulong)app_size; + config.reg_offset_shift = 0; + config.width = REGMAP_SIZE_32; + + priv->iomuxc_gpr = devm_regmap_init(dev, NULL, NULL, &config); + if (IS_ERR(priv->iomuxc_gpr)) { + dev_err(dev, "unable to remap gpr\n"); + ret = PTR_ERR(priv->iomuxc_gpr); + goto err_phy; + } } - priv->iomuxc_gpr = syscon_node_to_regmap(gpr); - if (IS_ERR(priv->iomuxc_gpr)) { - dev_err(dev, "unable to find iomuxc registers\n"); - ret = PTR_ERR(priv->iomuxc_gpr); - goto err_phy; + if (info->gpr) { + gpr = ofnode_by_compatible(ofnode_null(), info->gpr); + if (ofnode_equal(gpr, ofnode_null())) { + dev_err(dev, "unable to find GPR node\n"); + ret = -ENODEV; + goto err_phy; + } + + priv->iomuxc_gpr = syscon_node_to_regmap(gpr); + if (IS_ERR(priv->iomuxc_gpr)) { + dev_err(dev, "unable to find iomuxc registers\n"); + ret = PTR_ERR(priv->iomuxc_gpr); + goto err_phy; + } } + priv->max_link_speed = dev_read_u32_default(dev, "fsl,max-link-speed", LINK_SPEED_GEN_1); + + priv->supports_clkreq = dev_read_bool(dev, "supports-clkreq"); + /* vpcie-supply regulator is optional */ device_get_supply_regulator(dev, "vpcie-supply", &priv->vpcie); @@ -322,7 +645,8 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) err_phy: dm_gpio_free(dev, &priv->reset_gpio); err_gpio: - reset_free(&priv->apps_reset); + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_free(&priv->apps_reset); err_reset: clk_release_bulk(&priv->clks); @@ -337,6 +661,7 @@ static const struct dm_pci_ops pcie_dw_imx_ops = { static const struct udevice_id pcie_dw_imx_ids[] = { { .compatible = "fsl,imx8mm-pcie", .data = (ulong)&imx8mm_chip_info, }, { .compatible = "fsl,imx8mp-pcie", .data = (ulong)&imx8mp_chip_info, }, + { .compatible = "fsl,imx95-pcie", .data = (ulong)&imx95_chip_info, }, { } }; diff --git a/drivers/pci/pcie_intel_fpga.c b/drivers/pci/pcie_intel_fpga.c deleted file mode 100644 index 959fd369086..00000000000 --- a/drivers/pci/pcie_intel_fpga.c +++ /dev/null @@ -1,434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel FPGA PCIe host controller driver - * - * Copyright (C) 2013-2018 Intel Corporation. All rights reserved - * - */ - -#include <dm.h> -#include <pci.h> -#include <asm/global_data.h> -#include <asm/io.h> -#include <dm/device_compat.h> -#include <linux/bitops.h> -#include <linux/delay.h> - -#define RP_TX_REG0 0x2000 -#define RP_TX_CNTRL 0x2004 -#define RP_TX_SOP BIT(0) -#define RP_TX_EOP BIT(1) -#define RP_RXCPL_STATUS 0x200C -#define RP_RXCPL_SOP BIT(0) -#define RP_RXCPL_EOP BIT(1) -#define RP_RXCPL_REG 0x2008 -#define P2A_INT_STATUS 0x3060 -#define P2A_INT_STS_ALL 0xf -#define P2A_INT_ENABLE 0x3070 -#define RP_CAP_OFFSET 0x70 - -/* TLP configuration type 0 and 1 */ -#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ -#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ -#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */ -#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */ -#define TLP_PAYLOAD_SIZE 0x01 -#define TLP_READ_TAG 0x1d -#define TLP_WRITE_TAG 0x10 -#define RP_DEVFN 0 - -#define RP_CFG_ADDR(pcie, reg) \ - ((pcie->hip_base) + (reg) + (1 << 20)) -#define RP_SECONDARY(pcie) \ - readb(RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS)) -#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) - -#define TLP_CFGRD_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGRD1 \ - : TLP_FMTTYPE_CFGRD0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFGWR_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGWR1 \ - : TLP_FMTTYPE_CFGWR0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFG_DW1(pcie, tag, be) \ - (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be)) -#define TLP_CFG_DW2(bus, dev, fn, offset) \ - (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset)) - -#define TLP_COMP_STATUS(s) (((s) >> 13) & 7) -#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff) -#define TLP_HDR_SIZE 3 -#define TLP_LOOP 20000 -#define DWORD_MASK 3 - -#define IS_ROOT_PORT(pcie, bdf) \ - ((PCI_BUS(bdf) == pcie->first_busno) ? true : false) - -/** - * struct intel_fpga_pcie - Intel FPGA PCIe controller state - * @bus: Pointer to the PCI bus - * @cra_base: The base address of CRA register space - * @hip_base: The base address of Rootport configuration space - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup. - */ -struct intel_fpga_pcie { - struct udevice *bus; - void __iomem *cra_base; - void __iomem *hip_base; - int first_busno; -}; - -/** - * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the - * translation from PCI bus to native BUS. Entire DDR region is mapped - * into PCIe space using these registers, so it can be reached by DMA from - * EP devices. - * The BAR0 of bridge should be hidden during enumeration to avoid the - * sizing and resource allocation by PCIe core. - */ -static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, int offset) -{ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 && - PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0) - return true; - - return false; -} - -static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value, - const u32 reg) -{ - writel(value, pcie->cra_base + reg); -} - -static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg) -{ - return readl(pcie->cra_base + reg); -} - -static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie) -{ - return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA)) - & PCI_EXP_LNKSTA_DLLLA); -} - -static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie, - pci_dev_t bdf) -{ - /* If there is no link, then there is no device */ - if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie)) - return false; - - /* access only one slot on each root port */ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0) - return false; - - if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0) - return false; - - return true; -} - -static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl) -{ - cra_writel(pcie, reg0, RP_TX_REG0); - cra_writel(pcie, ctrl, RP_TX_CNTRL); -} - -static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value) -{ - int i; - u32 ctrl; - u32 comp_status; - u32 dw[4]; - u32 count = 0; - - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - if (!(ctrl & RP_RXCPL_SOP)) - continue; - - /* read first DW */ - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - - /* Poll for EOP */ - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - if (ctrl & RP_RXCPL_EOP) { - comp_status = TLP_COMP_STATUS(dw[1]); - if (comp_status) { - *value = pci_get_ff(PCI_SIZE_32); - return 0; - } - - if (value && - TLP_BYTE_COUNT(dw[1]) == sizeof(u32) && - count >= 3) - *value = dw[3]; - - return 0; - } - } - - udelay(5); - } - - dev_err(pcie->dev, "read TLP packet timed out\n"); - return -ENODEV; -} - -static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers, - u32 data) -{ - tlp_write_tx(pcie, headers[0], RP_TX_SOP); - - tlp_write_tx(pcie, headers[1], 0); - - tlp_write_tx(pcie, headers[2], 0); - - tlp_write_tx(pcie, data, RP_TX_EOP); -} - -static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 *value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGRD_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, 0); - - return tlp_read_packet(pcie, value); -} - -static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGWR_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, value); - - return tlp_read_packet(pcie, NULL); -} - -int intel_fpga_rp_conf_addr(const struct udevice *bus, pci_dev_t bdf, - uint offset, void **paddress) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - *paddress = RP_CFG_ADDR(pcie, offset); - - return 0; -} - -static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, valuep, size); -} - -static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - int ret; - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, value, size); - if (!ret) { - /* Monitor changes to PCI_PRIMARY_BUS register on root port - * and update local copy of root bus number accordingly. - */ - if (offset == PCI_PRIMARY_BUS) - pcie->first_busno = (u8)(value); - } - - return ret; -} - -static u8 pcie_get_byte_en(uint offset, enum pci_size_t size) -{ - switch (size) { - case PCI_SIZE_8: - return 1 << (offset & 3); - case PCI_SIZE_16: - return 3 << (offset & 3); - default: - return 0xf; - } -} - -static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong *valuep, enum pci_size_t size) -{ - int ret; - u32 data; - u8 byte_en; - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf, - offset, valuep, size); - - byte_en = pcie_get_byte_en(offset, size); - ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK, - byte_en, &data); - if (ret) - return ret; - - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n", - offset, size, data); - *valuep = pci_conv_32_to_size(data, offset, size); - - return 0; -} - -static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong value, enum pci_size_t size) -{ - u32 data; - u8 byte_en; - - dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", - offset, size, value); - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset, - value, size); - - byte_en = pcie_get_byte_en(offset, size); - data = pci_conv_size_to_32(0, value, offset, size); - - return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK, - byte_en, data); -} - -static int pcie_intel_fpga_read_config(const struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size); -} - -static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) - return 0; - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) - return 0; - - return _pcie_intel_fpga_write_config(pcie, bdf, offset, value, - size); -} - -static int pcie_intel_fpga_probe(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - - pcie->bus = pci_get_controller(dev); - pcie->first_busno = dev_seq(dev); - - /* clear all interrupts */ - cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS); - /* disable all interrupts */ - cra_writel(pcie, 0, P2A_INT_ENABLE); - - return 0; -} - -static int pcie_intel_fpga_of_to_plat(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - struct fdt_resource reg_res; - int node = dev_of_offset(dev); - int ret; - - DECLARE_GLOBAL_DATA_PTR; - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Cra", ®_res); - if (ret) { - dev_err(dev, "resource \"Cra\" not found\n"); - return ret; - } - - pcie->cra_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Hip", ®_res); - if (ret) { - dev_err(dev, "resource \"Hip\" not found\n"); - return ret; - } - - pcie->hip_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - return 0; -} - -static const struct dm_pci_ops pcie_intel_fpga_ops = { - .read_config = pcie_intel_fpga_read_config, - .write_config = pcie_intel_fpga_write_config, -}; - -static const struct udevice_id pcie_intel_fpga_ids[] = { - { .compatible = "altr,pcie-root-port-2.0" }, - {}, -}; - -U_BOOT_DRIVER(pcie_intel_fpga) = { - .name = "pcie_intel_fpga", - .id = UCLASS_PCI, - .of_match = pcie_intel_fpga_ids, - .ops = &pcie_intel_fpga_ops, - .of_to_plat = pcie_intel_fpga_of_to_plat, - .probe = pcie_intel_fpga_probe, - .priv_auto = sizeof(struct intel_fpga_pcie), -}; diff --git a/drivers/pci/pcie_iproc.c b/drivers/pci/pcie_iproc.c index 360ef1b011f..a6ed0189178 100644 --- a/drivers/pci/pcie_iproc.c +++ b/drivers/pci/pcie_iproc.c @@ -13,6 +13,7 @@ #include <dm/device_compat.h> #include <linux/delay.h> #include <linux/log2.h> +#include <linux/sizes.h> #define EP_PERST_SOURCE_SELECT_SHIFT 2 #define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT) diff --git a/drivers/pci/pcie_starfive_jh7110.c b/drivers/pci/pcie_starfive_jh7110.c index 51aca7359ff..0908ae16b67 100644 --- a/drivers/pci/pcie_starfive_jh7110.c +++ b/drivers/pci/pcie_starfive_jh7110.c @@ -292,8 +292,6 @@ static int starfive_pcie_probe(struct udevice *dev) if (ret) return ret; - dev_err(dev, "Starfive PCIe bus probed.\n"); - return 0; } diff --git a/drivers/phy/keystone-usb-phy.c b/drivers/phy/keystone-usb-phy.c index cfc15203d63..460efbe768d 100644 --- a/drivers/phy/keystone-usb-phy.c +++ b/drivers/phy/keystone-usb-phy.c @@ -41,7 +41,7 @@ static int keystone_usb_init(struct phy *phy) rc = psc_enable_module(keystone->psc_domain); if (rc) { debug("Cannot enable USB module"); - return -rc; + return rc; } mdelay(10); diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 714be123856..f8d4fb3b41b 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -274,7 +274,7 @@ int generic_phy_exit(struct phy *phy) { struct phy_counts *counts; struct phy_ops const *ops; - int ret; + int ret = 0; if (!generic_phy_valid(phy)) return 0; @@ -292,12 +292,11 @@ int generic_phy_exit(struct phy *phy) if (ret) { dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n", phy->dev->name, ret); - return ret; } } counts->init_count = 0; - return 0; + return ret; } int generic_phy_power_on(struct phy *phy) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index c69a342e2b4..6e2d4bc2b05 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1201,6 +1201,7 @@ static int j721e_wiz_probe(struct udevice *dev) if (num_lanes > WIZ_MAX_LANES) { dev_err(dev, "Cannot support %d lanes\n", num_lanes); + rc = -EINVAL; goto err_addr_to_resource; } diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 5e2808abc8a..48119694031 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -197,7 +197,7 @@ config PINCTRL_AR933X config PINCTRL_AT91 bool "AT91 pinctrl driver" - depends on DM + depends on DM && ARCH_AT91 help This option is to enable the AT91 pinctrl driver for AT91 PIO controller. @@ -213,13 +213,14 @@ config PINCTRL_AT91 config PINCTRL_AT91PIO4 bool "AT91 PIO4 pinctrl driver" - depends on DM + depends on DM && ARCH_AT91 help This option is to enable the AT91 pinctrl driver for AT91 PIO4 controller which is available on SAMA5D2 SoC. config PINCTRL_INTEL bool "Standard Intel pin-control and pin-mux driver" + depends on X86 help Recent Intel chips such as Apollo Lake (APL) use a common pin control and GPIO scheme. The settings for this come from an SoC-specific @@ -248,7 +249,7 @@ config PINCTRL_QCA953X config PINCTRL_QE bool "QE based pinctrl driver, like on mpc83xx" - depends on DM + depends on DM && MPC83xx help This option is to enable the QE pinctrl driver for QE based io controller. diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index babf1bccc96..7dbaf966f93 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -117,8 +117,26 @@ int meson_gpio_get(struct udevice *dev, unsigned int offset) struct meson_pinctrl *priv = dev_get_priv(dev->parent); unsigned int reg, bit; int ret; + enum gpio_func_t direction; + enum meson_reg_type reg_type; - ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, ®, + direction = meson_gpio_get_direction(dev, offset); + + switch (direction) { + case GPIOF_INPUT: + reg_type = REG_IN; + break; + + case GPIOF_OUTPUT: + reg_type = REG_OUT; + break; + + default: + dev_warn(dev, "Failed to get current direction of Pin %u\n", offset); + return -EINVAL; + } + + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, reg_type, ®, &bit); if (ret) return ret; diff --git a/drivers/pinctrl/nexell/pinctrl-s5pxx18.c b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c index e7d0994f29e..a6ae5764fbc 100644 --- a/drivers/pinctrl/nexell/pinctrl-s5pxx18.c +++ b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c @@ -130,7 +130,8 @@ static int is_pin_alive(const char *name) static int s5pxx18_pinctrl_set_state(struct udevice *dev, struct udevice *config) { - unsigned int count, idx, pin; + u32 pin; + int count, idx; unsigned int pinfunc, pinpud, pindrv; unsigned long reg; const char *name; diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index 67e564f85c3..c960ca3393d 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -23,6 +23,7 @@ #define TIPRSTC 0x50 #define CORSTC 0x5c #define FLOCKR1 0x74 +#define INTCR 0x3c #define INTCR4 0xc0 #define I2CSEGSEL 0xe0 #define MFSEL1 0x260 @@ -280,6 +281,7 @@ struct npcm8xx_pinctrl_priv { FUNC(lkgpo2, FLOCKR1, 8, 9) \ FUNC(nprd_smi, FLOCKR1, 20, 190) \ FUNC(mmcwp, FLOCKR1, 24, 153) \ + FUNC(vcdhs, INTCR, 27) \ FUNC(rg2refck, INTCR4, 6) \ FUNC(r1en, INTCR4, 12) \ FUNC(r2en, INTCR4, 13) \ diff --git a/drivers/pinctrl/nxp/pinctrl-imx-scmi.c b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c index aed47be337d..781835c6852 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx-scmi.c +++ b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c @@ -16,6 +16,7 @@ #include "pinctrl-imx.h" #define DAISY_OFFSET_IMX95 0x408 +#define DAISY_OFFSET_IMX94 0x608 /* SCMI pin control types */ #define PINCTRL_TYPE_MUX 192 @@ -133,6 +134,8 @@ static int imx_scmi_pinctrl_probe(struct udevice *dev) if (IS_ENABLED(CONFIG_IMX95)) priv->daisy_offset = DAISY_OFFSET_IMX95; + else if (IS_ENABLED(CONFIG_IMX94)) + priv->daisy_offset = DAISY_OFFSET_IMX94; else return -EINVAL; @@ -141,7 +144,7 @@ static int imx_scmi_pinctrl_probe(struct udevice *dev) static int imx_scmi_pinctrl_bind(struct udevice *dev) { - if (IS_ENABLED(CONFIG_IMX95)) + if (IS_ENABLED(CONFIG_IMX95) || IS_ENABLED(CONFIG_IMX94)) return 0; return -ENODEV; diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index a3802d22d4f..c96b293aadf 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -109,8 +109,6 @@ static unsigned int single_read(struct udevice *dev, void *reg) default: /* 32 bits */ return readl(reg); } - - return readb(reg); } static void single_write(struct udevice *dev, unsigned int val, void *reg) diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 61f335c4eb1..0d5778faef9 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -87,7 +87,7 @@ static int stmfx_read_reg(struct udevice *dev, u8 reg_base, uint offset) if (ret < 0) return ret; - return ret < 0 ? ret : !!(ret & mask); + return !!(ret & mask); } static int stmfx_write_reg(struct udevice *dev, u8 reg_base, uint offset, diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index 324d7af8fcd..0d64f4d5ad6 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -3,11 +3,14 @@ * Copyright (C) 2024, Exfo Inc - All Rights Reserved * * Author: Anis CHALI <anis.chali@exfo.com> - * inspired and adapted from linux driver of sx150x written by Gregory Bean - * <gbean@codeaurora.org> + * + * Inspired and adapted from the Linux pinctrl-sx150x driver: + * Copyright (c) 2016, BayLibre, SAS. All rights reserved. + * Author: Neil Armstrong <narmstrong@baylibre.com> + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Author: Gregory Bean <gbean@codeaurora.org> */ -#include <asm/gpio.h> #include <dm.h> #include <dm/device-internal.h> #include <dm/device.h> @@ -22,6 +25,8 @@ #include <log.h> #include <power/regulator.h> #include <regmap.h> +#include <linux/bug.h> +#include <asm/gpio.h> #define err(format, arg...) printf("ERR:" format "\n", ##arg) #define dbg(format, arg...) printf("DBG:" format "\n", ##arg) @@ -413,7 +418,7 @@ static int sx150x_reg_read(struct sx150x_pinctrl_priv *pctl, unsigned int reg, { int ret, n; const int width = sx150x_reg_width(pctl, reg); - unsigned int idx, val; + unsigned int val, idx; /* * There are four potential cases covered by this function: @@ -444,8 +449,9 @@ static int sx150x_reg_read(struct sx150x_pinctrl_priv *pctl, unsigned int reg, * reg 3 [ 3 3 2 2 1 1 0 0 ] */ - for (n = width, val = 0, idx = reg; n > 0; n -= 8, idx) { + for (n = width, val = 0; n > 0; n -= 8) { val <<= 8; + idx = reg; ret = dm_i2c_reg_read(pctl->i2c, idx); if (ret < 0) @@ -475,7 +481,6 @@ static int sx150x_reg_write(struct sx150x_pinctrl_priv *pctl, unsigned int reg, if (ret < 0) return ret; - reg; n -= 8; } while (n >= 0); @@ -724,7 +729,7 @@ static const struct udevice_id sx150x_pinctrl_of_match[] = { {}, }; -static const struct pinconf_param sx150x_conf_params[] = { +static const struct pinconf_param __maybe_unused sx150x_conf_params[] = { { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, @@ -750,7 +755,7 @@ static const char *sx150x_pinctrl_get_pin_name(struct udevice *dev, return pin_name; } -static int sx150x_pinctrl_conf_set(struct udevice *dev, unsigned int pin, +static int __maybe_unused sx150x_pinctrl_conf_set(struct udevice *dev, unsigned int pin, unsigned int param, unsigned int arg) { int ret; @@ -834,13 +839,11 @@ static int sx150x_pinctrl_conf_set(struct udevice *dev, unsigned int pin, static int sx150x_pinctrl_bind(struct udevice *dev) { struct sx150x_pinctrl_priv *pctl = dev_get_plat(dev); - int ret, reg; + int ret; if (!dev_read_bool(dev, "gpio-controller")) return 0; - reg = (int)dev_read_addr_ptr(dev); - ret = device_bind(dev, &sx150x_gpio_driver, dev_read_name(dev), NULL, dev_ofnode(dev), &pctl->gpio); if (ret) @@ -861,7 +864,10 @@ static int sx150x_pinctrl_probe(struct udevice *dev) pctl->data = drv_data; - reg = (int)dev_read_addr_ptr(dev); + reg = dev_read_u32_default(dev, "reg", -ENODEV); + if (reg < 0) + return -ENODEV; + ret = dm_i2c_probe(dev->parent, reg, 0, &pctl->i2c); if (ret) { err("Cannot find I2C chip %02x (%d)", reg, ret); diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c index be7e508f8a4..4eead0875d8 100644 --- a/drivers/pinctrl/pinctrl-th1520.c +++ b/drivers/pinctrl/pinctrl-th1520.c @@ -697,4 +697,5 @@ U_BOOT_DRIVER(th1520_pinctrl) = { .probe = th1520_pinctrl_probe, .priv_auto = sizeof(struct th1520_pinctrl), .ops = &th1520_pinctrl_ops, + .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/pinctrl/tegra/Kconfig b/drivers/pinctrl/tegra/Kconfig index 669d8e258e4..d2630289d75 100644 --- a/drivers/pinctrl/tegra/Kconfig +++ b/drivers/pinctrl/tegra/Kconfig @@ -2,7 +2,7 @@ config PINCTRL_TEGRA bool "Nvidia Tegra pinctrl driver" - depends on DM + depends on DM && ARCH_TEGRA help Support pin multiplexing control on Nvidia Tegra SoCs. The driver is an overlay to existing driver and allows @@ -11,7 +11,7 @@ config PINCTRL_TEGRA config SPL_PINCTRL_TEGRA bool "Nvidia Tegra SPL pinctrl driver" - depends on SPL_PINCTRL + depends on SPL_PINCTRL && ARCH_TEGRA help Enables support of pre-DM version of pin multiplexing control driver used on SPL stage for board setup and diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index eed65058e66..d17337c0c3f 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -15,6 +15,7 @@ if POWER config POWER_LEGACY bool "Legacy power support" + depends on !DM_PMIC help Note: This is a legacy option. Use DM_PMIC instead. @@ -462,6 +463,7 @@ config TWL4030_POWER config POWER_MT6323 bool "Poweroff driver for mediatek mt6323" + depends on ARCH_MEDIATEK select CMD_POWEROFF help This adds poweroff driver for mt6323 diff --git a/drivers/power/axp818.c b/drivers/power/axp818.c index 83ae6ecc138..01f9a209dc6 100644 --- a/drivers/power/axp818.c +++ b/drivers/power/axp818.c @@ -248,8 +248,6 @@ int axp_init(void) if (!(axp_chip_id == 0x51)) return -ENODEV; - else - return ret; return 0; } diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index ec7ccc3a63f..b1a5b1c2a1f 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -228,9 +228,9 @@ config PMIC_MAX8997 This is a Power Management IC with RTC, Fuel Gauge, MUIC control on Chip. - 21x LDOs - 12x GPIOs - - Haptic Motor driver + - Haptic motor driver - RTC with two alarms - - Fueal Gauge and One backup battery charger + - Fuel Gauge and one backup battery charger - MUIC - Others diff --git a/drivers/power/pmic/max8997.c b/drivers/power/pmic/max8997.c index 4afa6c84ef8..fb65a3ca730 100644 --- a/drivers/power/pmic/max8997.c +++ b/drivers/power/pmic/max8997.c @@ -46,7 +46,7 @@ static struct dm_pmic_ops max8997_ops = { }; static const struct udevice_id max8997_ids[] = { - { .compatible = "maxim,max8997" }, + { .compatible = "maxim,max8997-pmic" }, { }, }; diff --git a/drivers/power/pmic/pca9450.c b/drivers/power/pmic/pca9450.c index 9d875f8bdbe..e5c1f037b61 100644 --- a/drivers/power/pmic/pca9450.c +++ b/drivers/power/pmic/pca9450.c @@ -7,15 +7,16 @@ #include <errno.h> #include <dm.h> #include <dm/device_compat.h> +#include <dm/lists.h> #include <i2c.h> -#include <linux/err.h> #include <log.h> #include <asm/global_data.h> -#include <asm-generic/gpio.h> +#include <linux/delay.h> #include <linux/printk.h> #include <power/pmic.h> #include <power/regulator.h> #include <power/pca9450.h> +#include <sysreset.h> DECLARE_GLOBAL_DATA_PTR; @@ -29,10 +30,6 @@ static const struct pmic_child_info pmic_children_info[] = { { }, }; -struct pca9450_priv { - struct gpio_desc *sd_vsel_gpio; -}; - static int pca9450_reg_count(struct udevice *dev) { return PCA9450_REG_NUM; @@ -85,20 +82,15 @@ static int pca9450_bind(struct udevice *dev) static int pca9450_probe(struct udevice *dev) { - struct pca9450_priv *priv = dev_get_priv(dev); unsigned int reset_ctrl; - int ret = 0; - - if (CONFIG_IS_ENABLED(DM_GPIO) && CONFIG_IS_ENABLED(DM_REGULATOR_PCA9450)) { - priv->sd_vsel_gpio = devm_gpiod_get_optional(dev, "sd-vsel", - GPIOD_IS_OUT | - GPIOD_IS_OUT_ACTIVE); - if (IS_ERR(priv->sd_vsel_gpio)) { - ret = PTR_ERR(priv->sd_vsel_gpio); - dev_err(dev, "Failed to request SD_VSEL GPIO: %d\n", ret); - if (ret) - return ret; - } + int ret; + + if (CONFIG_IS_ENABLED(SYSRESET)) { + ret = device_bind_driver_to_node(dev, "pca9450_sysreset", + "pca9450_sysreset", + dev_ofnode(dev), NULL); + if (ret) + return ret; } if (ofnode_read_bool(dev_ofnode(dev), "nxp,wdog_b-warm-reset")) @@ -132,5 +124,73 @@ U_BOOT_DRIVER(pmic_pca9450) = { .bind = pca9450_bind, .probe = pca9450_probe, .ops = &pca9450_ops, - .priv_auto = sizeof(struct pca9450_priv), }; + +#ifdef CONFIG_SYSRESET +static int pca9450_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + u8 cmd = PCA9450_SW_RST_COLD_RST; + + if (type != SYSRESET_COLD) + return -EPROTONOSUPPORT; + + if (pmic_write(dev->parent, PCA9450_SW_RST, &cmd, 1)) { + dev_err(dev, "reset command failed\n"); + } else { + /* tRESTART is 250ms, delay 300ms just to be sure */ + mdelay(300); + /* Should not get here, warn if we do */ + dev_warn(dev, "didn't respond to reset command\n"); + } + + return -EINPROGRESS; +} + +int pca9450_sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + const char *reason; + int ret; + u8 reg; + + ret = pmic_read(dev->parent, PCA9450_PWRON_STAT, ®, 1); + if (ret) + return ret; + + switch (reg) { + case PCA9450_PWRON_STAT_PWRON_MASK: + reason = "PWRON"; + break; + case PCA9450_PWRON_STAT_WDOG_MASK: + reason = "WDOGB"; + break; + case PCA9450_PWRON_STAT_SW_RST_MASK: + reason = "SW_RST"; + break; + case PCA9450_PWRON_STAT_PMIC_RST_MASK: + reason = "PMIC_RST"; + break; + default: + reason = "UNKNOWN"; + break; + } + + ret = snprintf(buf, size, "Reset Status: %s\n", reason); + if (ret < 0) { + dev_err(dev, "Write reset status error (err = %d)\n", ret); + return -EIO; + } + + return 0; +} + +static struct sysreset_ops pca9450_sysreset_ops = { + .request = pca9450_sysreset_request, + .get_status = pca9450_sysreset_get_status, +}; + +U_BOOT_DRIVER(pca9450_sysreset) = { + .name = "pca9450_sysreset", + .id = UCLASS_SYSRESET, + .ops = &pca9450_sysreset_ops, +}; +#endif /* CONFIG_SYSRESET */ diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c index 17780017035..6e819579030 100644 --- a/drivers/power/pmic/s2mps11.c +++ b/drivers/power/pmic/s2mps11.c @@ -52,7 +52,7 @@ static int s2mps11_probe(struct udevice *dev) ofnode regulators_node; int children; - regulators_node = dev_read_subnode(dev, "voltage-regulators"); + regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { debug("%s: %s regulators subnode not found!\n", __func__, dev->name); diff --git a/drivers/power/power_i2c.c b/drivers/power/power_i2c.c index c2fc1c6b42f..58289ecce67 100644 --- a/drivers/power/power_i2c.c +++ b/drivers/power/power_i2c.c @@ -75,7 +75,7 @@ int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) { unsigned char buf[4] = { 0 }; u32 ret_val = 0; - int ret; + int __maybe_unused ret; if (check_reg(p, reg)) return -EINVAL; @@ -91,9 +91,9 @@ int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) return -ENXIO; } ret = dm_i2c_read(dev, reg, buf, pmic_i2c_tx_num); -#endif if (ret) return ret; +#endif switch (pmic_i2c_tx_num) { case 3: diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 65b99e89656..1875e61967c 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -143,7 +143,7 @@ config REGULATOR_PWM config SPL_REGULATOR_PWM bool "Enable Driver for PWM regulators in SPL" - depends on REGULATOR_PWM && SPL + depends on SPL_DM_REGULATOR && SPL && SPL_DM_PWM help This config enables implementation of driver-model regulator uclass features for PWM regulators in SPL. diff --git a/drivers/power/regulator/lp873x_regulator.c b/drivers/power/regulator/lp873x_regulator.c index 271a7e45139..62d91a23f77 100644 --- a/drivers/power/regulator/lp873x_regulator.c +++ b/drivers/power/regulator/lp873x_regulator.c @@ -83,8 +83,8 @@ static int lp873x_buck_hex2volt(int hex) static int lp873x_buck_val(struct udevice *dev, int op, int *uV) { - unsigned int hex, adr; - int ret; + unsigned int adr; + int hex, ret; struct dm_regulator_uclass_plat *uc_pdata; uc_pdata = dev_get_uclass_plat(dev); @@ -177,8 +177,8 @@ static int lp873x_ldo_hex2volt(int hex) static int lp873x_ldo_val(struct udevice *dev, int op, int *uV) { - unsigned int hex, adr; - int ret; + unsigned int adr; + int hex, ret; struct dm_regulator_uclass_plat *uc_pdata; diff --git a/drivers/power/regulator/lp87565_regulator.c b/drivers/power/regulator/lp87565_regulator.c index 2212cb5c651..ea9c7685e9f 100644 --- a/drivers/power/regulator/lp87565_regulator.c +++ b/drivers/power/regulator/lp87565_regulator.c @@ -82,8 +82,8 @@ static int lp87565_buck_val2volt(int val) static int lp87565_buck_val(struct udevice *dev, int op, int *uV) { - unsigned int hex, adr; - int ret; + unsigned int adr; + int hex, ret; struct dm_regulator_uclass_plat *uc_pdata; uc_pdata = dev_get_uclass_plat(dev); diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c index 2286eac93fb..7212062c8c8 100644 --- a/drivers/power/regulator/palmas_regulator.c +++ b/drivers/power/regulator/palmas_regulator.c @@ -115,8 +115,8 @@ static int palmas_smps_hex2volt(int hex, bool range) static int palmas_smps_val(struct udevice *dev, int op, int *uV) { - unsigned int hex, adr; - int ret; + unsigned int adr; + int hex, ret; bool range; struct dm_regulator_uclass_plat *uc_pdata; @@ -251,8 +251,8 @@ static int palmas_ldo_hex2volt(int hex) static int palmas_ldo_val(struct udevice *dev, int op, int *uV) { - unsigned int hex, adr; - int ret; + unsigned int adr; + int hex, ret; struct dm_regulator_uclass_plat *uc_pdata; diff --git a/drivers/power/regulator/pca9450.c b/drivers/power/regulator/pca9450.c index a2a34244723..3bb0c71dde7 100644 --- a/drivers/power/regulator/pca9450.c +++ b/drivers/power/regulator/pca9450.c @@ -7,9 +7,12 @@ * ROHM BD71837 regulator driver */ +#include <asm-generic/gpio.h> #include <dm.h> +#include <dm/device_compat.h> #include <log.h> #include <linux/bitops.h> +#include <linux/err.h> #include <power/pca9450.h> #include <power/pmic.h> #include <power/regulator.h> @@ -52,6 +55,8 @@ struct pca9450_plat { u8 volt_mask; struct pca9450_vrange *ranges; unsigned int numranges; + struct gpio_desc *sd_vsel_gpio; + bool sd_vsel_fixed_low; }; #define PCA_RANGE(_min, _vstep, _sel_low, _sel_hi) \ @@ -144,7 +149,7 @@ static struct pca9450_plat pca9450_reg_data[] = { PCA_DATA("LDO4", PCA9450_LDO4CTRL, HW_STATE_CONTROL, PCA9450_LDO4CTRL, PCA9450_LDO34_MASK, pca9450_ldo34_vranges), - PCA_DATA("LDO5", PCA9450_LDO5CTRL_H, HW_STATE_CONTROL, + PCA_DATA("LDO5", PCA9450_LDO5CTRL_L, HW_STATE_CONTROL, PCA9450_LDO5CTRL_H, PCA9450_LDO5_MASK, pca9450_ldo5_vranges), }; @@ -222,13 +227,24 @@ static int pca9450_set_enable(struct udevice *dev, bool enable) val); } +static u8 pca9450_get_vsel_reg(struct pca9450_plat *plat) +{ + if (!strcmp(plat->name, "LDO5") && + ((plat->sd_vsel_gpio && !dm_gpio_get_value(plat->sd_vsel_gpio)) || + plat->sd_vsel_fixed_low)) { + return PCA9450_LDO5CTRL_L; + } + + return plat->volt_reg; +} + static int pca9450_get_value(struct udevice *dev) { struct pca9450_plat *plat = dev_get_plat(dev); unsigned int reg, tmp; int i, ret; - ret = pmic_reg_read(dev->parent, plat->volt_reg); + ret = pmic_reg_read(dev->parent, pca9450_get_vsel_reg(plat)); if (ret < 0) return ret; @@ -274,7 +290,7 @@ static int pca9450_set_value(struct udevice *dev, int uvolt) if (!found) return -EINVAL; - return pmic_clrsetbits(dev->parent, plat->volt_reg, + return pmic_clrsetbits(dev->parent, pca9450_get_vsel_reg(plat), plat->volt_mask, sel); } @@ -335,6 +351,21 @@ static int pca9450_regulator_probe(struct udevice *dev) *plat = pca9450_reg_data[i]; + if (!strcmp(plat->name, "LDO5")) { + if (CONFIG_IS_ENABLED(DM_GPIO) && CONFIG_IS_ENABLED(DM_REGULATOR_PCA9450)) { + plat->sd_vsel_gpio = devm_gpiod_get_optional(dev, "sd-vsel", + GPIOD_IS_IN); + if (IS_ERR(plat->sd_vsel_gpio)) { + ret = PTR_ERR(plat->sd_vsel_gpio); + dev_err(dev, "Failed to request SD_VSEL GPIO: %d\n", ret); + if (ret) + return ret; + } + } + + plat->sd_vsel_fixed_low = dev_read_bool(dev, "nxp,sd-vsel-fixed-low"); + } + return 0; } diff --git a/drivers/power/regulator/pfuze100.c b/drivers/power/regulator/pfuze100.c index bf3a7019411..f864b1d8834 100644 --- a/drivers/power/regulator/pfuze100.c +++ b/drivers/power/regulator/pfuze100.c @@ -241,56 +241,46 @@ static struct dm_regulator_mode pfuze_ldo_modes[] = { MODE(LDO_MODE_ON, LDO_MODE_ON, "LDO_MODE_ON"), }; -static struct pfuze100_regulator_desc *se_desc(struct pfuze100_regulator_desc *desc, - int size, - const char *name) -{ - int i; - - for (i = 0; i < size; desc++) { - if (!strcmp(desc->name, name)) - return desc; - continue; - } - - return NULL; -} - static int pfuze100_regulator_probe(struct udevice *dev) { struct dm_regulator_uclass_plat *uc_pdata; struct pfuze100_regulator_plat *plat = dev_get_plat(dev); struct pfuze100_regulator_desc *desc; + int i, size; switch (dev_get_driver_data(dev_get_parent(dev))) { case PFUZE100: - desc = se_desc(pfuze100_regulators, - ARRAY_SIZE(pfuze100_regulators), - dev->name); + desc = pfuze100_regulators; + size = ARRAY_SIZE(pfuze100_regulators); break; case PFUZE200: - desc = se_desc(pfuze200_regulators, - ARRAY_SIZE(pfuze200_regulators), - dev->name); + desc = pfuze200_regulators; + size = ARRAY_SIZE(pfuze200_regulators); break; case PFUZE3000: - desc = se_desc(pfuze3000_regulators, - ARRAY_SIZE(pfuze3000_regulators), - dev->name); + desc = pfuze3000_regulators; + size = ARRAY_SIZE(pfuze3000_regulators); break; default: debug("Unsupported PFUZE\n"); return -EINVAL; } - if (!desc) { + + for (i = 0; i < size; i++) { + if (strcmp(desc[i].name, dev->name)) + continue; + break; + } + + if (i == size) { debug("Do not support regulator %s\n", dev->name); return -EINVAL; } - plat->desc = desc; + plat->desc = &desc[i]; uc_pdata = dev_get_uclass_plat(dev); - uc_pdata->type = desc->type; + uc_pdata->type = desc[i].type; if (uc_pdata->type == REGULATOR_TYPE_BUCK) { if (!strcmp(dev->name, "swbst")) { uc_pdata->mode = pfuze_swbst_modes; diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 2a59a1b79c2..94c52cf555b 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -389,7 +389,7 @@ int regulator_list_autoset(const char *list_platname[], ret = regulator_autoset_by_name(list_platname[i], &dev); if (ret != -EMEDIUMTYPE && verbose) regulator_show(dev, ret); - if (ret & !error) + if (ret && ret != -EALREADY && !error) error = ret; if (list_devp) diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index e3565d32a01..c80f10c3aa3 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -45,6 +45,16 @@ int regulator_common_of_to_plat(struct udevice *dev, dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); } + ret = device_get_supply_regulator(dev, "vin-supply", &plat->vin_supply); + if (ret) { + debug("Regulator vin regulator not defined: %d\n", ret); + if (ret != -ENOENT) + return ret; + } + + if (plat->vin_supply) + regulator_set_enable_if_allowed(plat->vin_supply, true); + return 0; } diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h index d4962899d83..799c968d0b6 100644 --- a/drivers/power/regulator/regulator_common.h +++ b/drivers/power/regulator/regulator_common.h @@ -14,6 +14,7 @@ struct regulator_common_plat { unsigned int startup_delay_us; unsigned int off_on_delay_us; unsigned int enable_count; + struct udevice *vin_supply; }; int regulator_common_of_to_plat(struct udevice *dev, diff --git a/drivers/power/regulator/rzg2l-usbphy-regulator.c b/drivers/power/regulator/rzg2l-usbphy-regulator.c index 451f04c140e..0354555d0b5 100644 --- a/drivers/power/regulator/rzg2l-usbphy-regulator.c +++ b/drivers/power/regulator/rzg2l-usbphy-regulator.c @@ -27,7 +27,7 @@ static int rzg2l_usbphy_regulator_get_enable(struct udevice *dev) { struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev->parent); - return !!readl(priv->regs + VBENCTL) & VBENCTL_VBUS_SEL; + return !!(readl(priv->regs + VBENCTL) & VBENCTL_VBUS_SEL); } static const struct dm_regulator_ops rzg2l_usbphy_regulator_ops = { diff --git a/drivers/power/regulator/tps65941_regulator.c b/drivers/power/regulator/tps65941_regulator.c index 13f94b730d4..2561d6f4c6c 100644 --- a/drivers/power/regulator/tps65941_regulator.c +++ b/drivers/power/regulator/tps65941_regulator.c @@ -277,8 +277,8 @@ static const struct tps65941_reg_conv_ops buck_conv_ops[] = { static int tps65941_buck_val(struct udevice *dev, int op, int *uV) { - unsigned int hex, adr; - int ret, delta, uwait, slew, idx; + unsigned int adr; + int hex, ret, delta, uwait, slew, idx; struct dm_regulator_uclass_plat *uc_pdata; const struct tps65941_reg_conv_ops *conv_ops; ulong chip_id; @@ -479,8 +479,8 @@ static const struct tps65941_reg_conv_ops ldo_conv_ops[] = { static int tps65941_ldo_val(struct udevice *dev, int op, int *uV) { - unsigned int hex, adr; - int ret, ret_volt, idx, ldo_bypass; + unsigned int adr; + int hex, ret, ret_volt, idx, ldo_bypass; struct dm_regulator_uclass_plat *uc_pdata; const struct tps65941_reg_conv_ops *conv_ops; ulong chip_id; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index e4c676d75c2..06f42f699de 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -42,7 +42,7 @@ config PWM_CROS_EC config PWM_EXYNOS bool "Enable support for the Exynos PWM" - depends on DM_PWM + depends on DM_PWM && ARCH_EXYNOS help This PWM is found on Samsung Exynos 5250 and other Samsung SoCs. It supports a programmable period and duty cycle. A 32-bit counter is @@ -51,6 +51,7 @@ config PWM_EXYNOS config PWM_IMX bool "Enable support for i.MX27 and later PWM" + depends on MACH_IMX help This PWM is found i.MX27 and later i.MX SoCs. @@ -70,7 +71,7 @@ config PWM_MTK config PWM_ROCKCHIP bool "Enable support for the Rockchip PWM" - depends on DM_PWM + depends on DM_PWM && ARCH_ROCKCHIP help This PWM is found on RK3288 and other Rockchip SoCs. It supports a programmable period and duty cycle. A 32-bit counter is used. @@ -98,7 +99,7 @@ config PWM_SIFIVE config PWM_TEGRA bool "Enable support for the Tegra PWM" - depends on DM_PWM + depends on DM_PWM && ARCH_TEGRA help This PWM is found on Tegra 20 and other Nvidia SoCs. It supports four channels with a programmable period and duty cycle. Only a @@ -115,7 +116,7 @@ config PWM_STM32 config PWM_SUNXI bool "Enable support for the Allwinner Sunxi PWM" - depends on DM_PWM + depends on DM_PWM && ARCH_SUNXI help This PWM is found on H3, A64 and other Allwinner SoCs. It supports a programmable period and duty cycle. A 16-bit counter is used. diff --git a/drivers/pwm/pwm-aspeed.c b/drivers/pwm/pwm-aspeed.c index ebc9d9a8975..eefe018448f 100644 --- a/drivers/pwm/pwm-aspeed.c +++ b/drivers/pwm/pwm-aspeed.c @@ -46,6 +46,7 @@ #include <regmap.h> #include <syscon.h> #include <dm/device_compat.h> +#include <linux/log2.h> #include <linux/math64.h> #include <linux/bitfield.h> #include <linux/time.h> diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index c2597d8b669..caa7af085fa 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -359,8 +359,9 @@ static int meson_pwm_probe(struct udevice *dev) /* We have our source clock, do not alter HW clock mux */ continue; - } else + } else if (err) { return err; + } /* Get id in list */ for (p = 0 ; p < data->num_parents ; ++p) { diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index 69b7de084e5..25880db37cf 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -255,7 +255,6 @@ void u_qe_init(void) struct mmc *mmc = find_mmc_device(CONFIG_ENV_MMC_DEVICE_INDEX); if (!mmc) { - free(addr); printf("\nMMC cannot find device for ucode\n"); } else { printf("\nMMC read: dev # %u, block # %u, count %u ...\n", diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index edb8e254d5b..cfbfa1252d0 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -39,7 +39,7 @@ config VPL_RAM config STM32_SDRAM bool "Enable STM32 SDRAM support" - depends on RAM + depends on RAM && ARCH_STM32 help STM32F7 family devices support flexible memory controller(FMC) to support external memories like sdram, psram & nand. @@ -47,7 +47,7 @@ config STM32_SDRAM config MPC83XX_SDRAM bool "Enable MPC83XX SDRAM support" - depends on RAM + depends on RAM && MPC83xx help Enable support for the internal DDR Memory Controller of the MPC83xx family of SoCs. Both static configurations, as well as configuring @@ -67,7 +67,7 @@ config K3_AM654_DDRSS config K3_DDRSS bool "Enable K3 DDRSS support" - depends on RAM + depends on RAM && ARCH_K3 choice depends on K3_DDRSS @@ -128,6 +128,16 @@ config K3_INLINE_ECC need to be primed with a predefined value prior to enabling ECC check. +config K3_MULTI_DDR + bool "Enable support for multiple K3 DDRSS controllers" + depends on K3_DDRSS + help + Enabling this option adds support for configuring multiple DDR memory + controllers for K3 devices. The external memory interleave layer + present in the MSMC (Multicore Shared Memory Controller) is + responsible for interleaving between the controllers. + default y if SOC_K3_J721S2 || SOC_K3_J784S4 + source "drivers/ram/aspeed/Kconfig" source "drivers/ram/cadence/Kconfig" source "drivers/ram/octeon/Kconfig" diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c index 6590d57ad84..5144470b931 100644 --- a/drivers/ram/k3-ddrss/k3-ddrss.c +++ b/drivers/ram/k3-ddrss/k3-ddrss.c @@ -59,6 +59,7 @@ #define SINGLE_DDR_SUBSYSTEM 0x1 #define MULTI_DDR_SUBSYSTEM 0x2 +#define MAX_MULTI_DDR 4 #define MULTI_DDR_CFG0 0x00114100 #define MULTI_DDR_CFG1 0x00114104 @@ -82,6 +83,24 @@ enum intrlv_gran { GRAN_16GB }; +u64 gran_bytes[] = { + 0x80, + 0x200, + 0x800, + 0x1000, + 0x4000, + 0x8000, + 0x80000, + 0x40000000, + 0x60000000, + 0x80000000, + 0xC0000000, + 0x100000000, + 0x180000000, + 0x200000000, + 0x400000000 +}; + enum intrlv_size { SIZE_0, SIZE_128MB, @@ -121,19 +140,21 @@ enum emif_active { EMIF_ALL }; +#define K3_DDRSS_MAX_ECC_REG 3 + +struct k3_ddrss_ecc_region { + u64 start; + u64 range; +}; + struct k3_msmc { enum intrlv_gran gran; enum intrlv_size size; enum ecc_enable enable; enum emif_config config; enum emif_active active; -}; - -#define K3_DDRSS_MAX_ECC_REGIONS 3 - -struct k3_ddrss_ecc_region { - u64 start; - u64 range; + u32 num_ddr_controllers; + struct k3_ddrss_ecc_region R0[MAX_MULTI_DDR]; }; struct k3_ddrss_desc { @@ -155,7 +176,8 @@ struct k3_ddrss_desc { lpddr4_obj *driverdt; lpddr4_config config; lpddr4_privatedata pd; - struct k3_ddrss_ecc_region ecc_regions[K3_DDRSS_MAX_ECC_REGIONS]; + struct k3_ddrss_ecc_region ecc_ranges[K3_DDRSS_MAX_ECC_REG]; + struct k3_ddrss_ecc_region ecc_regions[K3_DDRSS_MAX_ECC_REG]; u64 ecc_reserved_space; u64 ddr_bank_base[CONFIG_NR_DRAM_BANKS]; u64 ddr_bank_size[CONFIG_NR_DRAM_BANKS]; @@ -554,10 +576,26 @@ void k3_lpddr4_start(struct k3_ddrss_desc *ddrss) } } -static void k3_ddrss_set_ecc_range_r0(u32 base, u64 start_address, u64 size) +static void k3_ddrss_set_ecc_range_rx(u32 x, u32 base, u64 start_address, u64 size) { - writel((start_address) >> 16, base + DDRSS_ECC_R0_STR_ADDR_REG); - writel((start_address + size - 1) >> 16, base + DDRSS_ECC_R0_END_ADDR_REG); + u32 start_reg, end_reg; + + switch (x) { + case 1: + start_reg = DDRSS_ECC_R1_STR_ADDR_REG; + end_reg = DDRSS_ECC_R1_END_ADDR_REG; + break; + case 2: + start_reg = DDRSS_ECC_R2_STR_ADDR_REG; + end_reg = DDRSS_ECC_R2_END_ADDR_REG; + break; + default: + start_reg = DDRSS_ECC_R0_STR_ADDR_REG; + end_reg = DDRSS_ECC_R0_END_ADDR_REG; + break; + } + writel((start_address) >> 16, base + start_reg); + writel((start_address + size - 1) >> 16, base + end_reg); } #define BIST_MODE_MEM_INIT 4 @@ -626,7 +664,7 @@ static void k3_lpddr4_bist_init_mem_region(struct k3_ddrss_desc *ddrss, while (i < BIST_MEM_INIT_TIMEOUT) { status = driverdt->checkctlinterrupt(pd, LPDDR4_INTR_BIST_DONE, &int_status); - if (!status & int_status) { + if (!status && int_status) { /* Clear LPDDR4_INTR_BIST_DONE */ driverdt->ackctlinterrupt(pd, LPDDR4_INTR_BIST_DONE); break; @@ -733,10 +771,53 @@ static void k3_ddrss_ddr_reg_init(struct k3_ddrss_desc *ddrss) writel(DDRSS_ECC_CTRL_REG_DEFAULT, ddrss->ddrss_ss_cfg + DDRSS_ECC_CTRL_REG); } +ofnode get_next_ecc_node(ofnode ecc) +{ + do { + ecc = ofnode_by_prop_value(ecc, "device_type", "ecc", 4); + } while (!ofnode_is_enabled(ecc)); + + return ecc; +} + +static void k3_ddrss_ddr_inline_ecc_base_size_calc(struct k3_ddrss_ecc_region *range) +{ + fdt_addr_t base; + fdt_size_t size; + ofnode ecc_node = ofnode_null(); + + ecc_node = get_next_ecc_node(ecc_node); + if (!ofnode_valid(ecc_node)) { + debug("%s: No ECC node, enabling for entire region\n", __func__); + range->start = 0; + range->range = 0; + return; + } + + for (int i = 0; i < K3_DDRSS_MAX_ECC_REG; i++) { + base = ofnode_get_addr_size(ecc_node, "reg", &size); + if (base == FDT_ADDR_T_NONE) { + range->start = 0; + range->range = 0; + break; + } + range->start = base; + range->range = size; + range++; + ecc_node = get_next_ecc_node(ecc_node); + } +} + static void k3_ddrss_lpddr4_ecc_calc_reserved_mem(struct k3_ddrss_desc *ddrss) { fdtdec_setup_mem_size_base_lowest(); + /* + * For every 512-byte data block, 64 bytes are used to store inline ECC + * information into a reserved region. It remains 1/9th of the total DDR + * size irrespective of the size of the region under protection. + */ + ddrss->ecc_reserved_space = ddrss->ddr_ram_size; do_div(ddrss->ecc_reserved_space, 9); @@ -746,13 +827,21 @@ static void k3_ddrss_lpddr4_ecc_calc_reserved_mem(struct k3_ddrss_desc *ddrss) static void k3_ddrss_lpddr4_ecc_init(struct k3_ddrss_desc *ddrss) { - u64 ecc_region_start = ddrss->ecc_regions[0].start; - u64 ecc_range = ddrss->ecc_regions[0].range; + u64 ecc_region0_start = ddrss->ecc_regions[0].start; + u64 ecc_range0 = ddrss->ecc_regions[0].range; + u64 ecc_region1_start = ddrss->ecc_regions[1].start; + u64 ecc_range1 = ddrss->ecc_regions[1].range; + u64 ecc_region2_start = ddrss->ecc_regions[2].start; + u64 ecc_range2 = ddrss->ecc_regions[2].range; u32 base = (u32)ddrss->ddrss_ss_cfg; u32 val; /* Only Program region 0 which covers full ddr space */ - k3_ddrss_set_ecc_range_r0(base, ecc_region_start - ddrss->ddr_bank_base[0], ecc_range); + k3_ddrss_set_ecc_range_rx(0, base, ecc_region0_start, ecc_range0); + if (ecc_range1) + k3_ddrss_set_ecc_range_rx(1, base, ecc_region1_start, ecc_range1); + if (ecc_range2) + k3_ddrss_set_ecc_range_rx(2, base, ecc_region2_start, ecc_range2); /* Enable ECC, RMW, WR_ALLOC */ writel(DDRSS_ECC_CTRL_REG_ECC_EN | DDRSS_ECC_CTRL_REG_RMW_EN | @@ -777,8 +866,13 @@ static void k3_ddrss_lpddr4_ecc_init(struct k3_ddrss_desc *ddrss) static int k3_ddrss_probe(struct udevice *dev) { + u64 end, bank0, bank1, bank0_size; int ret; struct k3_ddrss_desc *ddrss = dev_get_priv(dev); + __maybe_unused u64 ddr_ram_size, ecc_res; + __maybe_unused u32 inst; + __maybe_unused struct k3_ddrss_ecc_region *range = ddrss->ecc_ranges; + __maybe_unused struct k3_msmc *msmc_parent = NULL; debug("%s(dev=%p)\n", __func__, dev); @@ -816,9 +910,75 @@ static int k3_ddrss_probe(struct udevice *dev) k3_ddrss_lpddr4_ecc_calc_reserved_mem(ddrss); - /* Always configure one region that covers full DDR space */ - ddrss->ecc_regions[0].start = ddrss->ddr_bank_base[0]; - ddrss->ecc_regions[0].range = ddrss->ddr_ram_size - ddrss->ecc_reserved_space; + k3_ddrss_ddr_inline_ecc_base_size_calc(range); + + bank0 = ddrss->ddr_bank_base[0]; + bank1 = ddrss->ddr_bank_base[1]; + bank0_size = ddrss->ddr_bank_size[0]; + + if (!range->range) { + /* Configure entire DDR space by default */ + debug("%s: Defaulting to protecting entire DDR space using inline ECC\n", + __func__); + ddrss->ecc_ranges[0].start = bank0; + ddrss->ecc_ranges[0].range = ddr_ram_size - ecc_res; + } else { + ddrss->ecc_ranges[0].start = range->start; + ddrss->ecc_ranges[0].range = range->range; + } + + if (!CONFIG_IS_ENABLED(K3_MULTI_DDR)) { + struct k3_ddrss_ecc_region *r = range; + + for (int i = 0; (i < K3_DDRSS_MAX_ECC_REG) && (r->range != 0); i++, r++) { + end = r->start + r->range; + ddr_ram_size = ddrss->ddr_ram_size; + ecc_res = ddrss->ecc_reserved_space; + + if (end > (ddr_ram_size - ecc_res)) + ddrss->ecc_regions[i].range = ddr_ram_size - ecc_res; + else + ddrss->ecc_regions[i].range = r->range; + + /* Check in which bank we are */ + if (r->start > bank1) + ddrss->ecc_regions[i].start = r->start - bank1 + bank0_size; + else + ddrss->ecc_regions[i].start = r->start - bank0; + } + } else { + /* For multi-DDR, we rely on MSMC's calculation of regions for each DDR */ + inst = ddrss->instance; + msmc_parent = kzalloc(sizeof(msmc_parent), GFP_KERNEL); + if (!msmc_parent) + return -ENOMEM; + + msmc_parent = dev_get_priv(dev->parent); + if (!msmc_parent) { + printf("%s: could not get MSMC parent to set up inline ECC regions\n", + __func__); + kfree(msmc_parent); + return -EINVAL; + } + + if (msmc_parent->R0[0].start < 0) { + /* Configure entire DDR space by default */ + ddrss->ecc_regions[0].start = bank0; + ddrss->ecc_regions[0].range = ddr_ram_size - ecc_res; + } else { + end = msmc_parent->R0[inst].start + msmc_parent->R0[inst].range; + + if (end > (ddr_ram_size - ecc_res)) + ddrss->ecc_regions[0].range = ddr_ram_size - ecc_res; + else + ddrss->ecc_regions[0].range = msmc_parent->R0[inst].range; + + ddrss->ecc_regions[0].start = msmc_parent->R0[inst].start; + } + + kfree(msmc_parent); + } + k3_ddrss_lpddr4_ecc_init(ddrss); } @@ -881,6 +1041,80 @@ U_BOOT_DRIVER(k3_ddrss) = { .priv_auto = sizeof(struct k3_ddrss_desc), }; +__maybe_unused static int k3_msmc_calculate_r0_regions(struct k3_msmc *msmc) +{ + u32 n1; + u32 size, ret = 0; + u32 gran = gran_bytes[msmc->gran]; + u32 num_ddr = msmc->num_ddr_controllers; + struct k3_ddrss_ecc_region *range = NULL; + struct k3_ddrss_ecc_region R[num_ddr]; + + range = kzalloc(sizeof(range), GFP_KERNEL); + if (!range) { + ret = -ENOMEM; + return ret; + } + + k3_ddrss_ddr_inline_ecc_base_size_calc(range); + + if (!range->range) { + ret = -EINVAL; + goto range_err; + } + + memset(R, 0, num_ddr); + + /* Find the first controller in the range */ + n1 = ((range->start / gran) % num_ddr); + size = range->range; + + if (size < gran) { + R[n1].start = range->start - 0x80000000; + R[n1].range = range->start + range->range - 0x80000000; + } else { + u32 chunk_start_addr = range->start; + u32 chunk_size = range->range; + + while (chunk_size > 0) { + u32 edge; + u32 end = range->start + range->range; + + if ((chunk_start_addr % gran) == 0) + edge = chunk_start_addr + gran; + else + edge = ((chunk_start_addr + (gran - 1)) & (-gran)); + + if (edge > end) + break; + + if (R[n1].start == 0) + R[n1].start = chunk_start_addr; + + R[n1].range = edge - R[n1].start; + chunk_size = end - edge; + chunk_start_addr = edge; + + if (n1 == (num_ddr - 1)) + n1 = 0; + else + n1++; + } + + for (int i = 0; i < num_ddr; i++) + R[i].start = (R[i].start - 0x80000000 - (gran * i)) / num_ddr; + } + + for (int i = 0; i < num_ddr; i++) { + msmc->R0[i].start = R[i].start; + msmc->R0[i].range = R[i].range; + } + +range_err: + free(range); + return ret; +} + static int k3_msmc_set_config(struct k3_msmc *msmc) { u32 ddr_cfg0 = 0; @@ -953,6 +1187,25 @@ static int k3_msmc_probe(struct udevice *dev) return -EINVAL; } + ret = device_get_child_count(dev); + if (ret <= 0) { + dev_err(dev, "no child ddr nodes present"); + return -EINVAL; + } + msmc->num_ddr_controllers = ret; + + if (IS_ENABLED(CONFIG_K3_MULTI_DDR) && IS_ENABLED(CONFIG_K3_INLINE_ECC)) { + ret = k3_msmc_calculate_r0_regions(msmc); + if (ret) { + /* Default to enabling inline ECC for entire DDR region */ + debug("%s: calculation of inline ECC regions failed, defaulting to entire region\n", + __func__); + + /* Use first R0 entry as a flag to denote MSMC calculation failure */ + msmc->R0[0].start = -1; + } + } + return 0; } diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index a3ecea05e20..e9f19a69433 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -125,6 +125,7 @@ config REMOTEPROC_TI_PRU config REMOTEPROC_TI_IPU bool "Support for TI's K3 based IPU remoteproc driver" select REMOTEPROC + depends on ARCH_K3 depends on DM depends on SPL_DRIVERS_MISC depends on SPL_FS_LOADER diff --git a/drivers/remoteproc/ti_k3_arm64_rproc.c b/drivers/remoteproc/ti_k3_arm64_rproc.c index d3eb957b2e4..403c6bed2e8 100644 --- a/drivers/remoteproc/ti_k3_arm64_rproc.c +++ b/drivers/remoteproc/ti_k3_arm64_rproc.c @@ -19,7 +19,7 @@ #include <linux/soc/ti/ti_sci_protocol.h> #include "ti_sci_proc.h" -#define INVALID_ID 0xffff +#define INVALID_ID 0xff #define GTC_CNTCR_REG 0x0 #define GTC_CNTFID0_REG 0x20 diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index f4bab6868ee..48401bc6eb6 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -233,7 +233,7 @@ static int k3_r5f_prepare(struct udevice *dev) dev_dbg(dev, "%s\n", __func__); - if (cluster->mode == CLUSTER_MODE_LOCKSTEP) + if ((cluster->mode == CLUSTER_MODE_LOCKSTEP) || (cluster->mode == CLUSTER_MODE_SINGLECPU)) ret = k3_r5f_lockstep_release(cluster); else ret = k3_r5f_split_release(core); @@ -269,6 +269,13 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core) return -EINVAL; } + if (cluster->mode == CLUSTER_MODE_SINGLECPU && !is_primary_core(core)) { + dev_err(core->dev, + "Invalid op: Trying to start secondary core %d in single CPU mode\n", + core->tsp.proc_id); + return -EINVAL; + } + if (cluster->mode == CLUSTER_MODE_SPLIT && !is_primary_core(core)) { if (!core->cluster->cores[0]->in_use) { dev_err(core->dev, @@ -441,7 +448,7 @@ proc_release: static int k3_r5f_split_reset(struct k3_r5f_core *core) { - int ret; + int ret = 0; dev_dbg(core->dev, "%s\n", __func__); @@ -476,7 +483,7 @@ static int k3_r5f_unprepare(struct udevice *dev) { struct k3_r5f_core *core = dev_get_priv(dev); struct k3_r5f_cluster *cluster = core->cluster; - int ret; + int ret = 0; dev_dbg(dev, "%s\n", __func__); @@ -768,7 +775,7 @@ static void k3_r5f_core_adjust_tcm_sizes(struct k3_r5f_core *core) { struct k3_r5f_cluster *cluster = core->cluster; - if (cluster->mode == CLUSTER_MODE_LOCKSTEP) + if ((cluster->mode == CLUSTER_MODE_LOCKSTEP) || (cluster->mode == CLUSTER_MODE_SINGLECPU)) return; if (!core->ipdata->tcm_is_double) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index e92bb8a7c39..74c267dfc4e 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -74,8 +74,8 @@ config RESET_UNIPHIER config RESET_AST2500 bool "Reset controller driver for AST2500 SoCs" - depends on DM_RESET - default y if ASPEED_AST2500 + depends on DM_RESET && ASPEED_AST2500 + default y help Support for reset controller on AST2500 SoC. Say Y if you want to control reset signals of different peripherals @@ -83,8 +83,8 @@ config RESET_AST2500 config RESET_AST2600 bool "Reset controller driver for AST2600 SoCs" - depends on DM_RESET - default y if ASPEED_AST2600 + depends on DM_RESET && ASPEED_AST2600 + default y help Support for reset controller on AST2600 SoC. Say Y if you want to control reset signals of different peripherals @@ -223,7 +223,7 @@ config RESET_ZYNQMP config RESET_DRA7 bool "Support for TI's DRA7 Reset driver" - depends on DM_RESET + depends on DM_RESET && ARCH_OMAP2PLUS help Support for TI DRA7-RESET subsystem. Basic Assert/Deassert is supported. diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index b35d8c66b9c..19b2b707677 100644 --- a/drivers/rng/Kconfig +++ b/drivers/rng/Kconfig @@ -40,7 +40,7 @@ config RNG_MSM config RNG_NPCM bool "Nuvoton NPCM SoCs Random Number Generator support" - depends on DM_RNG + depends on DM_RNG && !LIB_RAND help Enable random number generator on NPCM SoCs. This unit can provide 750 to 1000 random bits per second @@ -122,7 +122,7 @@ config RNG_TURRIS_RWTM config RNG_EXYNOS bool "Samsung Exynos True Random Number Generator support" - depends on DM_RNG + depends on DM_RNG && ARM help Enable support for True Random Number Generator (TRNG) available on Exynos SoCs. diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 79b879d68d1..ed903999f06 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -218,7 +218,7 @@ config RTC_PL031 config RTC_MV bool "Enable Marvell RTC driver" - depends on DM_RTC + depends on DM_RTC && ARCH_KIRKWOOD help Enable Marvell RTC driver. This driver supports the rtc that is present on some Marvell SoCs. diff --git a/drivers/rtc/ds1672.c b/drivers/rtc/ds1672.c index 4705e5abc93..651b1dc950f 100644 --- a/drivers/rtc/ds1672.c +++ b/drivers/rtc/ds1672.c @@ -108,7 +108,7 @@ static const struct udevice_id ds1672_of_id[] = { { } }; -U_BOOT_DRIVER(rtc_max313xx) = { +U_BOOT_DRIVER(rtc_ds1672) = { .name = "rtc-ds1672", .id = UCLASS_RTC, .probe = ds1672_probe, diff --git a/drivers/rtc/max313xx.c b/drivers/rtc/max313xx.c index 2cb3f245041..f0d38b10c97 100644 --- a/drivers/rtc/max313xx.c +++ b/drivers/rtc/max313xx.c @@ -308,6 +308,7 @@ static int max313xx_set_time(struct udevice *dev, const struct rtc_time *t) return ret; break; + case ID_MAX31331: case ID_MAX31343: /* Time is not updated for 1 second after writing */ /* Sleep here so the date command shows the new time */ diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index c0d86c6d063..08bc528aeaf 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -11,9 +11,9 @@ #include <command.h> #include <dm.h> #include <rtc.h> - -#if defined(CONFIG_X86) || defined(CONFIG_TARGET_MALTA) #include <asm/io.h> + +#if !defined(CONFIG_PPC) #define in8(p) inb(p) #define out8(p, v) outb(v, p) #endif diff --git a/drivers/rtc/pl031.c b/drivers/rtc/pl031.c index 855ee913416..6f189bc503e 100644 --- a/drivers/rtc/pl031.c +++ b/drivers/rtc/pl031.c @@ -39,11 +39,11 @@ static inline u32 pl031_read_reg(struct udevice *dev, int reg) return readl(pdata->base + reg); } -static inline u32 pl031_write_reg(struct udevice *dev, int reg, u32 value) +static inline void pl031_write_reg(struct udevice *dev, int reg, u32 value) { struct pl031_plat *pdata = dev_get_plat(dev); - return writel(value, pdata->base + reg); + writel(value, pdata->base + reg); } /* diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 1f2f2468eb0..bc05d2f1508 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -665,6 +665,7 @@ config ARM_DCC config ATMEL_USART bool "Atmel USART support" + depends on ARCH_AT91 help Select this to enable USART support for Atmel SoCs. It can be configured in the device tree, and input clock frequency can @@ -703,8 +704,8 @@ config BCM6345_SERIAL config COREBOOT_SERIAL bool "Coreboot UART support" - depends on DM_SERIAL - default y if SYS_COREBOOT + depends on DM_SERIAL && SYS_COREBOOT + default y select SYS_NS16550 help Select this to enable a ns16550-style UART where the platform data @@ -724,20 +725,14 @@ config COREBOOT_SERIAL_FROM_DBG2 config CORTINA_UART bool "Cortina UART support" - depends on DM_SERIAL + depends on DM_SERIAL && TARGET_PRESIDIO_ASIC help Select this to enable UART support for Cortina-Access UART devices found on CAxxxx SoCs. -config FSL_LINFLEXUART - bool "Freescale Linflex UART support" - depends on DM_SERIAL - help - Select this to enable the Linflex serial module found on some - NXP SoCs like S32V234. - config FSL_LPUART bool "Freescale LPUART support" + depends on MACH_IMX || ARCH_LS1021A || ARCH_LS1028A help Select this to enable a Low Power UART for Freescale VF610 and QorIQ Layerscape devices. @@ -748,12 +743,14 @@ config LPUART config MVEBU_A3700_UART bool "UART support for Armada 3700" + depends on ARCH_MVEBU help Choose this option to add support for UART driver on the Marvell Armada 3700 SoC. The base address is configured via DT. config MCFUART bool "Freescale ColdFire UART support" + depends on M68K help Choose this option to add support for UART driver on the ColdFire SoC's family. The serial communication channel provides a full-duplex @@ -879,7 +876,7 @@ config PL01X_SERIAL config ROCKCHIP_SERIAL bool "Rockchip on-chip UART support" - depends on DM_SERIAL + depends on DM_SERIAL && ARCH_ROCKCHIP select SYS_NS16550 help Select this to enable a debug UART for Rockchip devices when using @@ -1110,7 +1107,7 @@ config MTK_SERIAL config MT7620_SERIAL bool "UART driver for MediaTek MT7620 and earlier SoCs" - depends on DM_SERIAL + depends on DM_SERIAL && SOC_MT7620 help Select this to enable UART support for MediaTek MT7620 and earlier SoCs. This driver uses driver model and requires a device tree diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index c32e3fcd439..8eaae62b0fc 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_SCIF_CONSOLE) += serial_sh.o obj-$(CONFIG_SEMIHOSTING_SERIAL) += serial_semihosting.o obj-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o -obj-$(CONFIG_FSL_LINFLEXUART) += serial_linflexuart.o obj-$(CONFIG_ARC_SERIAL) += serial_arc.o obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index a08678dde4e..7b381ca12a0 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -191,7 +191,8 @@ int serial_init(void) { #if CONFIG_IS_ENABLED(SERIAL_PRESENT) serial_find_console_or_panic(); - gd->flags |= GD_FLG_SERIAL_READY; + if (gd->cur_serial_dev) + gd->flags |= GD_FLG_SERIAL_READY; if (IS_ENABLED(CONFIG_OF_SERIAL_BAUD)) { int ret = 0; diff --git a/drivers/serial/serial_linflexuart.c b/drivers/serial/serial_linflexuart.c deleted file mode 100644 index 24ecb236d51..00000000000 --- a/drivers/serial/serial_linflexuart.c +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2013-2016 Freescale Semiconductor, Inc. - */ - -#include <dm.h> -#include <errno.h> -#include <watchdog.h> -#include <asm/global_data.h> -#include <asm/io.h> -#include <serial.h> -#include <linux/compiler.h> -#include <asm/arch/imx-regs.h> -#include <asm/arch/clock.h> - -#define US1_TDRE (1 << 7) -#define US1_RDRF (1 << 5) -#define UC2_TE (1 << 3) -#define LINCR1_INIT (1 << 0) -#define LINCR1_MME (1 << 4) -#define LINCR1_BF (1 << 7) -#define LINSR_LINS_INITMODE (0x00001000) -#define LINSR_LINS_MASK (0x0000F000) -#define UARTCR_UART (1 << 0) -#define UARTCR_WL0 (1 << 1) -#define UARTCR_PCE (1 << 2) -#define UARTCR_PC0 (1 << 3) -#define UARTCR_TXEN (1 << 4) -#define UARTCR_RXEN (1 << 5) -#define UARTCR_PC1 (1 << 6) -#define UARTSR_DTF (1 << 1) -#define UARTSR_DRF (1 << 2) -#define UARTSR_RMB (1 << 9) - -DECLARE_GLOBAL_DATA_PTR; - -static void _linflex_serial_setbrg(struct linflex_fsl *base, int baudrate) -{ - u32 clk = mxc_get_clock(MXC_UART_CLK); - u32 ibr, fbr; - - if (!baudrate) - baudrate = CONFIG_BAUDRATE; - - ibr = (u32) (clk / (16 * gd->baudrate)); - fbr = (u32) (clk % (16 * gd->baudrate)) * 16; - - __raw_writel(ibr, &base->linibrr); - __raw_writel(fbr, &base->linfbrr); -} - -static int _linflex_serial_getc(struct linflex_fsl *base) -{ - char c; - - if (!(__raw_readb(&base->uartsr) & UARTSR_DRF)) - return -EAGAIN; - - if (!(__raw_readl(&base->uartsr) & UARTSR_RMB)) - return -EAGAIN; - - c = __raw_readl(&base->bdrm); - __raw_writeb((__raw_readb(&base->uartsr) | (UARTSR_DRF | UARTSR_RMB)), - &base->uartsr); - return c; -} - -static int _linflex_serial_putc(struct linflex_fsl *base, const char c) -{ - __raw_writeb(c, &base->bdrl); - - if (!(__raw_readb(&base->uartsr) & UARTSR_DTF)) - return -EAGAIN; - - __raw_writeb((__raw_readb(&base->uartsr) | UARTSR_DTF), &base->uartsr); - - return 0; -} - -/* - * Initialise the serial port with the given baudrate. The settings - * are always 8 data bits, no parity, 1 stop bit, no start bits. - */ -static int _linflex_serial_init(struct linflex_fsl *base) -{ - volatile u32 ctrl; - - /* set the Linflex in master mode amd activate by-pass filter */ - ctrl = LINCR1_BF | LINCR1_MME; - __raw_writel(ctrl, &base->lincr1); - - /* init mode */ - ctrl |= LINCR1_INIT; - __raw_writel(ctrl, &base->lincr1); - - /* waiting for init mode entry - TODO: add a timeout */ - while ((__raw_readl(&base->linsr) & LINSR_LINS_MASK) != - LINSR_LINS_INITMODE); - - /* set UART bit to allow writing other bits */ - __raw_writel(UARTCR_UART, &base->uartcr); - - /* provide data bits, parity, stop bit, etc */ - serial_setbrg(); - - /* 8 bit data, no parity, Tx and Rx enabled, UART mode */ - __raw_writel(UARTCR_PC1 | UARTCR_RXEN | UARTCR_TXEN | UARTCR_PC0 - | UARTCR_WL0 | UARTCR_UART, &base->uartcr); - - ctrl = __raw_readl(&base->lincr1); - ctrl &= ~LINCR1_INIT; - __raw_writel(ctrl, &base->lincr1); /* end init mode */ - - return 0; -} - -struct linflex_serial_plat { - struct linflex_fsl *base_addr; - u8 port_id; /* do we need this? */ -}; - -struct linflex_serial_priv { - struct linflex_fsl *lfuart; -}; - -int linflex_serial_setbrg(struct udevice *dev, int baudrate) -{ - struct linflex_serial_priv *priv = dev_get_priv(dev); - - _linflex_serial_setbrg(priv->lfuart, baudrate); - - return 0; -} - -static int linflex_serial_getc(struct udevice *dev) -{ - struct linflex_serial_priv *priv = dev_get_priv(dev); - - return _linflex_serial_getc(priv->lfuart); -} - -static int linflex_serial_putc(struct udevice *dev, const char ch) -{ - - struct linflex_serial_priv *priv = dev_get_priv(dev); - - return _linflex_serial_putc(priv->lfuart, ch); -} - -static int linflex_serial_pending(struct udevice *dev, bool input) -{ - struct linflex_serial_priv *priv = dev_get_priv(dev); - uint32_t uartsr = __raw_readl(&priv->lfuart->uartsr); - - if (input) - return ((uartsr & UARTSR_DRF) && (uartsr & UARTSR_RMB)) ? 1 : 0; - else - return uartsr & UARTSR_DTF ? 0 : 1; -} - -static void linflex_serial_init_internal(struct linflex_fsl *lfuart) -{ - _linflex_serial_init(lfuart); - _linflex_serial_setbrg(lfuart, CONFIG_BAUDRATE); - return; -} - -static int linflex_serial_probe(struct udevice *dev) -{ - struct linflex_serial_plat *plat = dev_get_plat(dev); - struct linflex_serial_priv *priv = dev_get_priv(dev); - - priv->lfuart = (struct linflex_fsl *)plat->base_addr; - linflex_serial_init_internal(priv->lfuart); - - return 0; -} - -static const struct dm_serial_ops linflex_serial_ops = { - .putc = linflex_serial_putc, - .pending = linflex_serial_pending, - .getc = linflex_serial_getc, - .setbrg = linflex_serial_setbrg, -}; - -U_BOOT_DRIVER(serial_linflex) = { - .name = "serial_linflex", - .id = UCLASS_SERIAL, - .probe = linflex_serial_probe, - .ops = &linflex_serial_ops, - .flags = DM_FLAG_PRE_RELOC, - .priv_auto = sizeof(struct linflex_serial_priv), -}; - -#ifdef CONFIG_DEBUG_UART_LINFLEXUART - -#include <debug_uart.h> - -static inline void _debug_uart_init(void) -{ - struct linflex_fsl *base = (struct linflex_fsl *)CONFIG_VAL(DEBUG_UART_BASE); - - linflex_serial_init_internal(base); -} - -static inline void _debug_uart_putc(int ch) -{ - struct linflex_fsl *base = (struct linflex_fsl *)CONFIG_VAL(DEBUG_UART_BASE); - - /* XXX: Is this OK? Should this use the non-DM version? */ - _linflex_serial_putc(base, ch); -} - -DEBUG_UART_FUNCS - -#endif /* CONFIG_DEBUG_UART_LINFLEXUART */ diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c index 93602797b83..9fdb6503085 100644 --- a/drivers/serial/serial_lpuart.c +++ b/drivers/serial/serial_lpuart.c @@ -129,7 +129,7 @@ static int get_lpuart_clk_rate(struct udevice *dev, u32 *clk_rate) rate = clk_get_rate(&clk); if ((long)rate <= 0) { dev_err(dev, "Failed to get clk rate: %ld\n", (long)rate); - return ret; + return rate; } *clk_rate = rate; return 0; diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c index eb234108746..6bfd0e085e8 100644 --- a/drivers/serial/serial_xuartlite.c +++ b/drivers/serial/serial_xuartlite.c @@ -32,6 +32,14 @@ struct uartlite { }; struct uartlite_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_serial_uartlite dtplat; +#else + struct uartlite *regs; +#endif +}; + +struct uartlite_priv { struct uartlite *regs; }; @@ -53,8 +61,8 @@ static void uart_out32(void __iomem *addr, u32 val) static int uartlite_serial_putc(struct udevice *dev, const char ch) { - struct uartlite_plat *plat = dev_get_plat(dev); - struct uartlite *regs = plat->regs; + struct uartlite_priv *priv = dev_get_priv(dev); + struct uartlite *regs = priv->regs; if (uart_in32(®s->status) & SR_TX_FIFO_FULL) return -EAGAIN; @@ -66,8 +74,8 @@ static int uartlite_serial_putc(struct udevice *dev, const char ch) static int uartlite_serial_getc(struct udevice *dev) { - struct uartlite_plat *plat = dev_get_plat(dev); - struct uartlite *regs = plat->regs; + struct uartlite_priv *priv = dev_get_priv(dev); + struct uartlite *regs = priv->regs; if (!(uart_in32(®s->status) & SR_RX_FIFO_VALID_DATA)) return -EAGAIN; @@ -77,8 +85,8 @@ static int uartlite_serial_getc(struct udevice *dev) static int uartlite_serial_pending(struct udevice *dev, bool input) { - struct uartlite_plat *plat = dev_get_plat(dev); - struct uartlite *regs = plat->regs; + struct uartlite_priv *priv = dev_get_priv(dev); + struct uartlite *regs = priv->regs; if (input) return uart_in32(®s->status) & SR_RX_FIFO_VALID_DATA; @@ -89,9 +97,19 @@ static int uartlite_serial_pending(struct udevice *dev, bool input) static int uartlite_serial_probe(struct udevice *dev) { struct uartlite_plat *plat = dev_get_plat(dev); - struct uartlite *regs = plat->regs; + struct uartlite_priv *priv = dev_get_priv(dev); + struct uartlite *regs; int ret; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_serial_uartlite *dtplat = &plat->dtplat; + + regs = (struct uartlite *)dtplat->reg[0]; +#else + regs = plat->regs; +#endif + priv->regs = regs; + uart_out32(®s->control, 0); uart_out32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); ret = uart_in32(®s->status); @@ -105,6 +123,7 @@ static int uartlite_serial_probe(struct udevice *dev) return 0; } +#if !CONFIG_IS_ENABLED(OF_PLATDATA) static int uartlite_serial_of_to_plat(struct udevice *dev) { struct uartlite_plat *plat = dev_get_plat(dev); @@ -113,6 +132,7 @@ static int uartlite_serial_of_to_plat(struct udevice *dev) return 0; } +#endif static const struct dm_serial_ops uartlite_serial_ops = { .putc = uartlite_serial_putc, @@ -130,12 +150,17 @@ U_BOOT_DRIVER(serial_uartlite) = { .name = "serial_uartlite", .id = UCLASS_SERIAL, .of_match = uartlite_serial_ids, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) .of_to_plat = uartlite_serial_of_to_plat, +#endif + .priv_auto = sizeof(struct uartlite_priv), .plat_auto = sizeof(struct uartlite_plat), .probe = uartlite_serial_probe, .ops = &uartlite_serial_ops, }; +DM_DRIVER_ALIAS(serial_uartlite, xlnx_xps_uartlite_1_00_a) + #ifdef CONFIG_DEBUG_UART_UARTLITE #include <debug_uart.h> diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig index 926af286330..8e500ed2ede 100644 --- a/drivers/sm/Kconfig +++ b/drivers/sm/Kconfig @@ -1,8 +1,17 @@ config SM - bool "Enable Secure Monitor driver support" + bool config MESON_SM bool "Amlogic Secure Monitor driver" + depends on ARCH_MESON select SM help Say y here to enable the Amlogic secure monitor driver. + +config SANDBOX_SM + bool "Sandbox Secure Monitor driver" + depends on SANDBOX + select SM + help + Say y here to enable the Sandbox driver for the secure monitor + uclass. diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile index da81ee898ab..5ac947350bd 100644 --- a/drivers/sm/Makefile +++ b/drivers/sm/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += sm-uclass.o -obj-$(CONFIG_SANDBOX) += sandbox-sm.o +obj-$(CONFIG_SM) += sm-uclass.o +obj-$(CONFIG_SANDBOX_SM) += sandbox-sm.o obj-$(CONFIG_MESON_SM) += meson-sm.o diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 4aa7833930c..8243805e46a 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -4,6 +4,7 @@ # menuconfig SOC_QCOM bool "Qualcomm SOC drivers support" + depends on ARM64 help Say Y here if you want to enable Qualcomm SOC drivers support. diff --git a/drivers/soc/ti/k3-navss-ringacc.c b/drivers/soc/ti/k3-navss-ringacc.c index 14114a65830..d37c454143b 100644 --- a/drivers/soc/ti/k3-navss-ringacc.c +++ b/drivers/soc/ti/k3-navss-ringacc.c @@ -632,12 +632,14 @@ err_free_ops: int k3_nav_ringacc_ring_cfg(struct k3_nav_ring *ring, struct k3_nav_ring_cfg *cfg) { - struct k3_nav_ringacc *ringacc = ring->parent; + struct k3_nav_ringacc *ringacc; int ret = 0; if (!ring || !cfg) return -EINVAL; + ringacc = ring->parent; + if (ringacc->dual_ring) return k3_dmaring_ring_cfg(ring, cfg); @@ -930,7 +932,7 @@ static int k3_nav_ringacc_probe_dt(struct k3_nav_ringacc *ringacc) ringacc->num_rings = dev_read_u32_default(dev, "ti,num-rings", 0); if (!ringacc->num_rings) { - dev_err(dev, "ti,num-rings read failure %d\n", ret); + dev_err(dev, "ti,num-rings read failure\n"); return -EINVAL; } diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig index 0948d8caab0..81de9b30f39 100644 --- a/drivers/sound/Kconfig +++ b/drivers/sound/Kconfig @@ -23,7 +23,7 @@ config I2S config I2S_ROCKCHIP bool "Enable I2S support for Rockchip SoCs" - depends on I2S + depends on I2S && ARCH_ROCKCHIP help Rockchip SoCs support an I2S interface for sending audio data to an audio codec. This option enables support for this, using one of the @@ -32,7 +32,7 @@ config I2S_ROCKCHIP config I2S_SAMSUNG bool "Enable I2C support for Samsung SoCs" - depends on I2S + depends on I2S && ARCH_EXYNOS help Samsung Exynos SoCs support an I2S interface for sending audio data to an audio codec. This option enables support for this, @@ -51,7 +51,7 @@ config SOUND_DA7219 config SOUND_I8254 bool "Intel i8254 timer / beeper" - depends on SOUND + depends on SOUND && X86 help This enables support for a beeper that uses the i8254 timer chip. This can emit beeps at a fixed frequency. It is possible to control @@ -82,7 +82,7 @@ config SOUND_IVYBRIDGE config I2S_TEGRA bool "Enable I2S support for Nvidia Tegra SoCs" - depends on I2S + depends on I2S && ARCH_TEGRA select TEGRA124_DMA help Nvidia Tegra SoCs support several I2S interfaces for sending audio diff --git a/drivers/sound/maxim_codec.c b/drivers/sound/maxim_codec.c index 98f094c0e9a..505a739ad7d 100644 --- a/drivers/sound/maxim_codec.c +++ b/drivers/sound/maxim_codec.c @@ -45,7 +45,7 @@ unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg, { int ret; - return dm_i2c_read(priv->dev, reg, data, 1); + ret = dm_i2c_read(priv->dev, reg, data, 1); if (ret != 0) { debug("%s: Error while reading register %#04x\n", __func__, reg); diff --git a/drivers/sound/rt5677.c b/drivers/sound/rt5677.c index b5c997c6dd5..a9d1e94951a 100644 --- a/drivers/sound/rt5677.c +++ b/drivers/sound/rt5677.c @@ -94,8 +94,8 @@ static int rt5677_i2c_write(struct rt5677_priv *priv, uint reg, uint data) static int rt5677_bic_or(struct rt5677_priv *priv, uint reg, uint bic, uint set) { - uint old, new_value; - int ret; + uint new_value; + int old, ret; old = rt5677_i2c_read(priv, reg); if (old < 0) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 1ae36b5a348..2960822211a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -530,6 +530,14 @@ config SPI_SUNXI Same controller driver can reuse in all Allwinner SoC variants. +config STM32_OSPI + bool "STM32MP2 OSPI driver" + depends on STM32MP25X && STM32_OMM + help + Enable the STM32MP2 Octo-SPI (OSPI) driver. This driver can be + used to access the SPI NOR flash chips on platforms embedding + this ST IP core. + config STM32_QSPI bool "STM32F7 QSPI driver" depends on STM32F4 || STM32F7 || ARCH_STM32MP diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index da91b18b6ed..5129d649f84 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o obj-$(CONFIG_SPI_SN_F_OSPI) += spi-sn-f-ospi.o obj-$(CONFIG_SPI_SUNXI) += spi-sunxi.o obj-$(CONFIG_SH_QSPI) += sh_qspi.o +obj-$(CONFIG_STM32_OSPI) += stm32_ospi.o obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o obj-$(CONFIG_STM32_SPI) += stm32_spi.o obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index 545561ad116..412993ad377 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -473,7 +473,9 @@ static int fsl_dspi_child_pre_probe(struct udevice *dev) priv->ctar_val[slave_plat->cs[0]] = DSPI_CTAR_DEFAULT_VALUE | DSPI_CTAR_PCSSCK(pcssck) | - DSPI_CTAR_PASC(pasc); + DSPI_CTAR_CSSCK(cssck) | + DSPI_CTAR_PASC(pasc) | + DSPI_CTAR_ASC(asc); debug("DSPI pre_probe slave device on CS %u, max_hz %u, mode 0x%x.\n", slave_plat->cs[0], slave_plat->max_hz, slave_plat->mode); diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c index 6d97b8eefc9..7086a2a264a 100644 --- a/drivers/spi/nxp_fspi.c +++ b/drivers/spi/nxp_fspi.c @@ -337,6 +337,33 @@ static struct nxp_fspi_devtype_data imxrt1170_data = { .little_endian = true, }; +static const struct nxp_fspi_devtype_data imx8qxp_data = { + .rxfifo = SZ_512, /* (64 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = 0, + .lut_num = 32, + .little_endian = true, /* little-endian */ +}; + +static const struct nxp_fspi_devtype_data imx8dxl_data = { + .rxfifo = SZ_512, /* (64 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = FSPI_QUIRK_USE_IP_ONLY, + .lut_num = 32, + .little_endian = true, /* little-endian */ +}; + +static const struct nxp_fspi_devtype_data imx8ulp_data = { + .rxfifo = SZ_1K, /* (128 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = 0, + .lut_num = 16, + .little_endian = true, /* little-endian */ +}; + struct nxp_fspi { struct udevice *dev; void __iomem *iobase; @@ -539,6 +566,15 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f, fspi_writel(f, lutval[i], base + target_lut_reg); } + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN && + op->addr.nbytes) { + lut_offset = (f->devtype_data->lut_num - 2) * 4 * 4; + for (i = 0; i < ARRAY_SIZE(lutval); i++) { + target_lut_reg = FSPI_LUT_BASE + lut_offset + i * 4; + fspi_writel(f, lutval[i], base + target_lut_reg); + } + } + dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n", op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes); @@ -943,9 +979,10 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) /* * The driver only uses one single LUT entry, that is updated on * each call of exec_op(). Index 0 is preset at boot with a basic - * read operation, so let's use the last entry. + * read operation, last entry is used for dynamic lut, the second + * last entry is used for AHB read. */ - seqid_lut = f->devtype_data->lut_num - 1; + seqid_lut = f->devtype_data->lut_num - 2; /* AHB Read - Set lut sequence ID for all CS. */ fspi_writel(f, seqid_lut, base + FSPI_FLSHA1CR2); fspi_writel(f, seqid_lut, base + FSPI_FLSHA2CR2); @@ -1071,6 +1108,9 @@ static const struct udevice_id nxp_fspi_ids[] = { { .compatible = "nxp,lx2160a-fspi", .data = (ulong)&lx2160a_data, }, { .compatible = "nxp,imx8mm-fspi", .data = (ulong)&imx8mm_data, }, { .compatible = "nxp,imx8mp-fspi", .data = (ulong)&imx8mm_data, }, + { .compatible = "nxp,imx8qxp-fspi", .data = (ulong)&imx8qxp_data, }, + { .compatible = "nxp,imx8dxl-fspi", .data = (ulong)&imx8dxl_data, }, + { .compatible = "nxp,imx8ulp-fspi", .data = (ulong)&imx8ulp_data, }, { .compatible = "nxp,imxrt1170-fspi", .data = (ulong)&imxrt1170_data, }, { } }; diff --git a/drivers/spi/stm32_ospi.c b/drivers/spi/stm32_ospi.c new file mode 100644 index 00000000000..01b8f8e4987 --- /dev/null +++ b/drivers/spi/stm32_ospi.c @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2025, STMicroelectronics - All Rights Reserved + */ + +#define LOG_CATEGORY UCLASS_SPI + +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <reset.h> +#include <spi.h> +#include <spi-mem.h> +#include <syscon.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> +#include <linux/sizes.h> + +/* OCTOSPI control register */ +#define OSPI_CR 0x00 +#define OSPI_CR_EN BIT(0) +#define OSPI_CR_ABORT BIT(1) +#define OSPI_CR_TCEN BIT(3) +#define OSPI_CR_FSEL BIT(7) +#define OSPI_CR_FTHRES_MASK GENMASK(13, 8) +#define OSPI_CR_FTHRES_SHIFT 8 +#define OSPI_CR_CSSEL BIT(24) +#define OSPI_CR_FMODE_SHIFT 28 +#define OSPI_CR_FMODE_MASK GENMASK(29, 28) + +/* OCTOSPI device configuration register */ +#define OSPI_DCR1 0x08 +#define OSPI_DCR1_CKMODE BIT(0) +#define OSPI_DCR1_DLYBYP BIT(3) +#define OSPI_DCR1_CSHT_SHIFT 8 +#define OSPI_DCR1_CSHT_MASK GENMASK(13, 8) +#define OSPI_DCR1_DEVSIZE_MASK GENMASK(20, 16) +#define OSPI_DCR1_MTYP_MASK GENMASK(26, 24) + +/* OCTOSPI device configuration register 2 */ +#define OSPI_DCR2 0x0c +#define OSPI_DCR2_PRESC_SHIFT 0 +#define OSPI_DCR2_PRESC_MASK GENMASK(7, 0) + +/* OCTOSPI status register */ +#define OSPI_SR 0x20 +#define OSPI_SR_TEF BIT(0) +#define OSPI_SR_TCF BIT(1) +#define OSPI_SR_FTF BIT(2) +#define OSPI_SR_BUSY BIT(5) + +/* OCTOSPI flag clear register */ +#define OSPI_FCR 0x24 +#define OSPI_FCR_CTEF BIT(0) +#define OSPI_FCR_CTCF BIT(1) + +/* OCTOSPI data length register */ +#define OSPI_DLR 0x40 + +/* OCTOSPI address register */ +#define OSPI_AR 0x48 + +/* OCTOSPI data configuration register */ +#define OSPI_DR 0x50 + +/* OCTOSPI communication configuration register */ +#define OSPI_CCR 0x100 +#define OSPI_CCR_IMODE_SHIFT 0 +#define OSPI_CCR_IMODE_MASK GENMASK(2, 0) +#define OSPI_CCR_ADMODE_SHIFT 8 +#define OSPI_CCR_ADMODE_MASK GENMASK(10, 8) +#define OSPI_CCR_ADSIZE_SHIFT 12 +#define OSPI_CCR_DMODE_SHIFT 24 +#define OSPI_CCR_DMODE_MASK GENMASK(26, 24) +#define OSPI_CCR_IND_WRITE 0 +#define OSPI_CCR_IND_READ 1 +#define OSPI_CCR_MEM_MAP 3 + +/* OCTOSPI timing configuration register */ +#define OSPI_TCR 0x108 +#define OSPI_TCR_DCYC_SHIFT 0x0 +#define OSPI_TCR_DCYC_MASK GENMASK(4, 0) +#define OSPI_TCR_SSHIFT BIT(30) + +/* OCTOSPI instruction register */ +#define OSPI_IR 0x110 + +#define OSPI_MAX_MMAP_SZ SZ_256M +#define OSPI_MAX_CHIP 2 + +#define OSPI_FIFO_TIMEOUT_US 30000 +#define OSPI_ABT_TIMEOUT_US 100000 +#define OSPI_BUSY_TIMEOUT_US 100000 +#define OSPI_CMD_TIMEOUT_US 1000000 + +struct stm32_ospi_flash { + u32 cr; + u32 dcr; + u32 dcr2; + bool initialized; +}; + +struct stm32_ospi_priv { + struct stm32_ospi_flash flash[OSPI_MAX_CHIP]; + int cs_used; +}; + +struct stm32_ospi_plat { + phys_addr_t regs_base; /* register base address */ + phys_addr_t mm_base; /* memory map base address */ + resource_size_t mm_size; + struct clk clk; + struct reset_ctl_bulk rst_ctl; + ulong clock_rate; +}; + +static int stm32_ospi_mm(struct udevice *dev, + const struct spi_mem_op *op) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(dev); + + memcpy_fromio(op->data.buf.in, + (void __iomem *)ospi_plat->mm_base + op->addr.val, + op->data.nbytes); + + return 0; +} + +static void stm32_ospi_read_fifo(void *val, phys_addr_t addr, u8 len) +{ + switch (len) { + case sizeof(u32): + *((u32 *)val) = readl_relaxed(addr); + break; + case sizeof(u16): + *((u16 *)val) = readw_relaxed(addr); + break; + case sizeof(u8): + *((u8 *)val) = readb_relaxed(addr); + }; + schedule(); +} + +static void stm32_ospi_write_fifo(void *val, phys_addr_t addr, u8 len) +{ + switch (len) { + case sizeof(u32): + writel_relaxed(*((u32 *)val), addr); + break; + case sizeof(u16): + writew_relaxed(*((u16 *)val), addr); + break; + case sizeof(u8): + writeb_relaxed(*((u8 *)val), addr); + }; +} + +int stm32_ospi_tx_poll(struct udevice *dev, void *buf, u32 len, bool read) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(dev); + phys_addr_t regs_base = ospi_plat->regs_base; + void (*fifo)(void *val, phys_addr_t addr, u8 len); + u32 sr; + int ret; + u8 step = 1; + + if (read) + fifo = stm32_ospi_read_fifo; + else + fifo = stm32_ospi_write_fifo; + + while (len) { + ret = readl_poll_timeout(regs_base + OSPI_SR, sr, + sr & OSPI_SR_FTF, + OSPI_FIFO_TIMEOUT_US); + if (ret) { + dev_err(dev, "fifo timeout (len:%d stat:%#x)\n", + len, sr); + return ret; + } + + if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) { + if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16))) + step = sizeof(u8); + else + step = min((u32)len, (u32)sizeof(u16)); + } + /* Buf is aligned */ + else if (len >= sizeof(u32)) + step = sizeof(u32); + else if (len >= sizeof(u16)) + step = sizeof(u16); + else if (len) + step = sizeof(u8); + + fifo(buf, regs_base + OSPI_DR, step); + len -= step; + buf += step; + } + + return 0; +} + +static int stm32_ospi_tx(struct udevice *dev, + const struct spi_mem_op *op, + u8 mode) +{ + void *buf; + + if (!op->data.nbytes) + return 0; + + if (mode == OSPI_CCR_MEM_MAP) + return stm32_ospi_mm(dev, op); + + if (op->data.dir == SPI_MEM_DATA_IN) + buf = op->data.buf.in; + else + buf = (void *)op->data.buf.out; + + return stm32_ospi_tx_poll(dev, buf, op->data.nbytes, + op->data.dir == SPI_MEM_DATA_IN); +} + +static int stm32_ospi_get_mode(u8 buswidth) +{ + if (buswidth == 8) + return 4; + + if (buswidth == 4) + return 3; + + return buswidth; +} + +int stm32_ospi_wait_for_not_busy(struct udevice *dev) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(dev); + phys_addr_t regs_base = ospi_plat->regs_base; + u32 sr; + int ret; + + ret = readl_poll_timeout(regs_base + OSPI_SR, sr, !(sr & OSPI_SR_BUSY), + OSPI_BUSY_TIMEOUT_US); + if (ret) + dev_err(dev, "busy timeout (stat:%#x)\n", sr); + + return ret; +} + +int stm32_ospi_wait_cmd(struct udevice *dev) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(dev); + phys_addr_t regs_base = ospi_plat->regs_base; + u32 sr; + int ret = 0; + + ret = readl_poll_timeout(regs_base + OSPI_SR, sr, + sr & OSPI_SR_TCF, + OSPI_CMD_TIMEOUT_US); + if (ret) { + dev_err(dev, "cmd timeout (stat:%#x)\n", sr); + } else if (readl(regs_base + OSPI_SR) & OSPI_SR_TEF) { + dev_err(dev, "transfer error (stat:%#x)\n", sr); + ret = -EIO; + } + + /* clear flags */ + writel(OSPI_FCR_CTCF | OSPI_FCR_CTEF, regs_base + OSPI_FCR); + + if (!ret) + ret = stm32_ospi_wait_for_not_busy(dev); + + return ret; +} + +static int stm32_ospi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(slave->dev->parent); + phys_addr_t regs_base = ospi_plat->regs_base; + u32 cr, ccr = 0, addr_max; + int timeout, ret; + int dmode; + u8 mode = OSPI_CCR_IND_WRITE; + u8 dcyc = 0; + + dev_dbg(slave->dev, "%s: cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", + __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, + op->dummy.buswidth, op->data.buswidth, + op->addr.val, op->data.nbytes); + + addr_max = op->addr.val + op->data.nbytes + 1; + + if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) { + if (addr_max < ospi_plat->mm_size && op->addr.buswidth) + mode = OSPI_CCR_MEM_MAP; + else + mode = OSPI_CCR_IND_READ; + } + + if (op->data.nbytes) + writel(op->data.nbytes - 1, regs_base + OSPI_DLR); + + clrsetbits_le32(regs_base + OSPI_CR, OSPI_CR_FMODE_MASK, + mode << OSPI_CR_FMODE_SHIFT); + + ccr |= (stm32_ospi_get_mode(op->cmd.buswidth) << OSPI_CCR_IMODE_SHIFT) & + OSPI_CCR_IMODE_MASK; + + if (op->addr.nbytes) { + ccr |= ((op->addr.nbytes - 1) << OSPI_CCR_ADSIZE_SHIFT); + ccr |= (stm32_ospi_get_mode(op->addr.buswidth) + << OSPI_CCR_ADMODE_SHIFT) & OSPI_CCR_ADMODE_MASK; + } + + if (op->dummy.buswidth && op->dummy.nbytes) + dcyc = op->dummy.nbytes * 8 / op->dummy.buswidth; + + clrsetbits_le32(regs_base + OSPI_TCR, OSPI_TCR_DCYC_MASK, + dcyc << OSPI_TCR_DCYC_SHIFT); + + if (op->data.nbytes) { + dmode = stm32_ospi_get_mode(op->data.buswidth); + ccr |= (dmode << OSPI_CCR_DMODE_SHIFT) & OSPI_CCR_DMODE_MASK; + } + + writel(ccr, regs_base + OSPI_CCR); + + /* set instruction, must be set after ccr register update */ + writel(op->cmd.opcode, regs_base + OSPI_IR); + + if (op->addr.nbytes && mode != OSPI_CCR_MEM_MAP) + writel(op->addr.val, regs_base + OSPI_AR); + + ret = stm32_ospi_tx(slave->dev->parent, op, mode); + /* + * Abort in: + * -error case + * -read memory map: prefetching must be stopped if we read the last + * byte of device (device size - fifo size). like device size is not + * knows, the prefetching is always stop. + */ + if (ret || mode == OSPI_CCR_MEM_MAP) + goto abort; + + /* Wait end of tx in indirect mode */ + ret = stm32_ospi_wait_cmd(slave->dev->parent); + if (ret) + goto abort; + + return 0; + +abort: + setbits_le32(regs_base + OSPI_CR, OSPI_CR_ABORT); + + /* Wait clear of abort bit by hw */ + timeout = readl_poll_timeout(regs_base + OSPI_CR, cr, + !(cr & OSPI_CR_ABORT), + OSPI_ABT_TIMEOUT_US); + + writel(OSPI_FCR_CTCF, regs_base + OSPI_FCR); + + if (ret || timeout) + dev_err(slave->dev, "%s ret:%d abort timeout:%d\n", __func__, + ret, timeout); + + return ret; +} + +static int stm32_ospi_probe(struct udevice *bus) +{ + struct stm32_ospi_priv *priv = dev_get_priv(bus); + struct stm32_ospi_plat *ospi_plat; + phys_addr_t regs_base; + int ret; + + ospi_plat = dev_get_plat(bus); + regs_base = ospi_plat->regs_base; + + ret = clk_enable(&ospi_plat->clk); + if (ret) { + dev_err(bus, "failed to enable clock\n"); + return ret; + } + + /* Reset OSPI controller */ + reset_assert_bulk(&ospi_plat->rst_ctl); + udelay(2); + reset_deassert_bulk(&ospi_plat->rst_ctl); + + priv->cs_used = -1; + + setbits_le32(regs_base + OSPI_TCR, OSPI_TCR_SSHIFT); + + clrsetbits_le32(regs_base + OSPI_CR, OSPI_CR_FTHRES_MASK, + 3 << OSPI_CR_FTHRES_SHIFT); + + /* Set dcr devsize to max address */ + setbits_le32(regs_base + OSPI_DCR1, + OSPI_DCR1_DEVSIZE_MASK | OSPI_DCR1_DLYBYP); + + return 0; +} + +static int stm32_ospi_claim_bus(struct udevice *dev) +{ + struct stm32_ospi_priv *priv = dev_get_priv(dev->parent); + struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); + struct stm32_ospi_plat *ospi_plat = dev_get_plat(dev->parent); + phys_addr_t regs_base = ospi_plat->regs_base; + unsigned int slave_cs = slave_plat->cs[0]; + + if (slave_cs >= OSPI_MAX_CHIP) + return -ENODEV; + + if (priv->cs_used != slave_cs) { + struct stm32_ospi_flash *flash = &priv->flash[slave_cs]; + + priv->cs_used = slave_cs; + + if (flash->initialized) { + /* Set the configuration: speed + cs */ + writel(flash->cr, regs_base + OSPI_CR); + writel(flash->dcr, regs_base + OSPI_DCR1); + writel(flash->dcr2, regs_base + OSPI_DCR2); + } else { + /* Set chip select */ + clrsetbits_le32(regs_base + OSPI_CR, + OSPI_CR_CSSEL, + priv->cs_used ? OSPI_CR_CSSEL : 0); + + /* Save the configuration: speed + cs */ + flash->cr = readl(regs_base + OSPI_CR); + flash->dcr = readl(regs_base + OSPI_DCR1); + flash->dcr2 = readl(regs_base + OSPI_DCR2); + flash->initialized = true; + } + } + + setbits_le32(regs_base + OSPI_CR, OSPI_CR_EN); + + return 0; +} + +static int stm32_ospi_release_bus(struct udevice *dev) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(dev->parent); + phys_addr_t regs_base = ospi_plat->regs_base; + + clrbits_le32(regs_base + OSPI_CR, OSPI_CR_EN); + + return 0; +} + +static int stm32_ospi_set_speed(struct udevice *bus, uint speed) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(bus); + phys_addr_t regs_base = ospi_plat->regs_base; + u32 ospi_clk = ospi_plat->clock_rate; + u32 prescaler = 255; + u32 csht; + int ret; + + if (speed > 0) { + prescaler = 0; + if (ospi_clk) { + prescaler = DIV_ROUND_UP(ospi_clk, speed) - 1; + if (prescaler > 255) + prescaler = 255; + } + } + + csht = (DIV_ROUND_UP((5 * ospi_clk) / (prescaler + 1), 100000000)) - 1; + + ret = stm32_ospi_wait_for_not_busy(bus); + if (ret) + return ret; + + clrsetbits_le32(regs_base + OSPI_DCR2, OSPI_DCR2_PRESC_MASK, + prescaler << OSPI_DCR2_PRESC_SHIFT); + + clrsetbits_le32(regs_base + OSPI_DCR1, OSPI_DCR1_CSHT_MASK, + csht << OSPI_DCR1_CSHT_SHIFT); + + return 0; +} + +static int stm32_ospi_set_mode(struct udevice *bus, uint mode) +{ + struct stm32_ospi_plat *ospi_plat = dev_get_plat(bus); + phys_addr_t regs_base = ospi_plat->regs_base; + const char *str_rx, *str_tx; + int ret; + + ret = stm32_ospi_wait_for_not_busy(bus); + if (ret) + return ret; + + if ((mode & SPI_CPHA) && (mode & SPI_CPOL)) + setbits_le32(regs_base + OSPI_DCR1, OSPI_DCR1_CKMODE); + else if (!(mode & SPI_CPHA) && !(mode & SPI_CPOL)) + clrbits_le32(regs_base + OSPI_DCR1, OSPI_DCR1_CKMODE); + else + return -ENODEV; + + if (mode & SPI_CS_HIGH) + return -ENODEV; + + if (mode & SPI_RX_OCTAL) + str_rx = "octal"; + else if (mode & SPI_RX_QUAD) + str_rx = "quad"; + else if (mode & SPI_RX_DUAL) + str_rx = "dual"; + else + str_rx = "single"; + + if (mode & SPI_TX_OCTAL) + str_tx = "octal"; + else if (mode & SPI_TX_QUAD) + str_tx = "quad"; + else if (mode & SPI_TX_DUAL) + str_tx = "dual"; + else + str_tx = "single"; + + dev_dbg(bus, "mode=%d rx: %s, tx: %s\n", mode, str_rx, str_tx); + + return 0; +} + +static const struct spi_controller_mem_ops stm32_ospi_mem_ops = { + .exec_op = stm32_ospi_exec_op, +}; + +static const struct dm_spi_ops stm32_ospi_ops = { + .claim_bus = stm32_ospi_claim_bus, + .release_bus = stm32_ospi_release_bus, + .set_speed = stm32_ospi_set_speed, + .set_mode = stm32_ospi_set_mode, + .mem_ops = &stm32_ospi_mem_ops, +}; + +static int stm32_ospi_of_to_plat(struct udevice *dev) +{ + struct stm32_ospi_plat *plat = dev_get_plat(dev); + struct resource res; + struct ofnode_phandle_args args; + const fdt32_t *reg; + int ret, len; + + reg = dev_read_prop(dev, "reg", &len); + if (!reg) { + dev_err(dev, "Can't get regs base address\n"); + return -ENOENT; + } + + plat->regs_base = (phys_addr_t)dev_translate_address(dev, reg); + + /* optional */ + ret = dev_read_phandle_with_args(dev, "memory-region", NULL, 0, 0, &args); + if (!ret) { + ret = ofnode_read_resource(args.node, 0, &res); + if (ret) { + dev_err(dev, "Can't get mmap base address(%d)\n", ret); + return ret; + } + + plat->mm_base = res.start; + plat->mm_size = resource_size(&res); + + if (plat->mm_size > OSPI_MAX_MMAP_SZ) { + dev_err(dev, "Incorrect memory-map size: %lld Bytes\n", plat->mm_size); + return -EINVAL; + } + + dev_dbg(dev, "%s: regs_base=<0x%llx> mm_base=<0x%llx> mm_size=<0x%x>\n", + __func__, plat->regs_base, plat->mm_base, (u32)plat->mm_size); + } else { + plat->mm_base = 0; + plat->mm_size = 0; + dev_info(dev, "memory-region property not found (%d)\n", ret); + } + + ret = clk_get_by_index(dev, 0, &plat->clk); + if (ret < 0) { + dev_err(dev, "Failed to get clock\n"); + return ret; + } + + ret = reset_get_bulk(dev, &plat->rst_ctl); + if (ret && ret != -ENOENT) { + dev_err(dev, "Failed to get reset\n"); + return ret; + } + + plat->clock_rate = clk_get_rate(&plat->clk); + if (!plat->clock_rate) + return -EINVAL; + + return ret; +}; + +static const struct udevice_id stm32_ospi_ids[] = { + { .compatible = "st,stm32mp25-ospi" }, + { } +}; + +U_BOOT_DRIVER(stm32_ospi) = { + .name = "stm32_ospi", + .id = UCLASS_SPI, + .of_match = stm32_ospi_ids, + .of_to_plat = stm32_ospi_of_to_plat, + .ops = &stm32_ospi_ops, + .plat_auto = sizeof(struct stm32_ospi_plat), + .priv_auto = sizeof(struct stm32_ospi_priv), + .probe = stm32_ospi_probe, +}; diff --git a/drivers/spmi/spmi-sandbox.c b/drivers/spmi/spmi-sandbox.c index 992b08dd612..1a8561b3aea 100644 --- a/drivers/spmi/spmi-sandbox.c +++ b/drivers/spmi/spmi-sandbox.c @@ -144,7 +144,7 @@ static const struct udevice_id sandbox_spmi_ids[] = { { } }; -U_BOOT_DRIVER(msm_spmi) = { +U_BOOT_DRIVER(sandbox_spmi) = { .name = "sandbox_spmi", .id = UCLASS_SPMI, .of_match = sandbox_spmi_ids, diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index 67edf004205..0181f6cd581 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -283,6 +283,7 @@ config SYSRESET_TPL_X86 config SYSRESET_MPC83XX bool "Enable support MPC83xx SoC family reboot driver" + depends on PPC help Reboot support for NXP MPC83xx SoCs. diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 440eb64a566..91c39aa4dee 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -35,6 +35,14 @@ config IMX_TMU The boot is hold to the cool device to throttle CPUs when the passive trip is crossed +config RCAR_GEN3_THERMAL + bool "Renesas R-Car Gen3/Gen4 and RZ/G2 thermal driver" + depends on ARCH_RENESAS + depends on RCAR_64 + help + Enable this to plug the R-Car Gen3/Gen4 or RZ/G2 thermal sensor + driver into the U-Boot thermal framework. + config TI_DRA7_THERMAL bool "Temperature sensor driver for TI dra7xx SOCs" help diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index b5ab0fc221f..b6f06c00ed9 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -4,9 +4,10 @@ # Author: Nitin Garg <nitin.garg@freescale.com> obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o -obj-$(CONFIG_SANDBOX) += thermal_sandbox.o -obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o -obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o +obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_IMX_TMU) += imx_tmu.o +obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o +obj-$(CONFIG_SANDBOX) += thermal_sandbox.o +obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o obj-$(CONFIG_TI_LM74_THERMAL) += ti-lm74.o diff --git a/drivers/thermal/imx_scu_thermal.c b/drivers/thermal/imx_scu_thermal.c index fc2b0e227b2..6b0b1d10d9d 100644 --- a/drivers/thermal/imx_scu_thermal.c +++ b/drivers/thermal/imx_scu_thermal.c @@ -72,7 +72,7 @@ int imx_sc_thermal_get_temp(struct udevice *dev, int *temp) break; } - *temp = cpu_temp / 1000; + *temp = cpu_temp; return 0; } diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index ea1fcc3dcb2..d04035950ee 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -223,7 +223,7 @@ int imx_thermal_get_temp(struct udevice *dev, int *temp) cpu_tmp = read_cpu_temperature(dev); } - *temp = cpu_tmp; + *temp = cpu_tmp * 1000; return 0; } diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index 70d002aee25..51a072e23c6 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -245,7 +245,7 @@ int imx_tmu_get_temp(struct udevice *dev, int *temp) return ret; } - *temp = cpu_tmp / 1000; + *temp = cpu_tmp; return 0; } diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c new file mode 100644 index 00000000000..45e590535a0 --- /dev/null +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R-Car Gen3/Gen4 and RZ/G2 THS thermal sensor driver + * Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen. + * + * Copyright (C) 2016 Renesas Electronics Corporation. + * Copyright (C) 2016 Sang Engineering + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <linux/delay.h> +#include <thermal.h> + +/* Register offsets */ +#define REG_GEN3_IRQSTR 0x04 +#define REG_GEN3_IRQMSK 0x08 +#define REG_GEN3_IRQCTL 0x0c +#define REG_GEN3_IRQEN 0x10 +#define REG_GEN3_IRQTEMP1 0x14 +#define REG_GEN3_IRQTEMP2 0x18 +#define REG_GEN3_IRQTEMP3 0x1c +#define REG_GEN3_THCTR 0x20 +#define REG_GEN3_TEMP 0x28 +#define REG_GEN3_THCODE1 0x50 +#define REG_GEN3_THCODE2 0x54 +#define REG_GEN3_THCODE3 0x58 +#define REG_GEN3_PTAT1 0x5c +#define REG_GEN3_PTAT2 0x60 +#define REG_GEN3_PTAT3 0x64 +#define REG_GEN3_THSCP 0x68 +#define REG_GEN4_THSFMON00 0x180 +#define REG_GEN4_THSFMON01 0x184 +#define REG_GEN4_THSFMON02 0x188 +#define REG_GEN4_THSFMON15 0x1bc +#define REG_GEN4_THSFMON16 0x1c0 +#define REG_GEN4_THSFMON17 0x1c4 + +/* IRQ{STR,MSK,EN} bits */ +#define IRQ_TEMP1 BIT(0) +#define IRQ_TEMP2 BIT(1) +#define IRQ_TEMP3 BIT(2) +#define IRQ_TEMPD1 BIT(3) +#define IRQ_TEMPD2 BIT(4) +#define IRQ_TEMPD3 BIT(5) + +/* THCTR bits */ +#define THCTR_PONM BIT(6) +#define THCTR_THSST BIT(0) + +/* THSCP bits */ +#define THSCP_COR_PARA_VLD (BIT(15) | BIT(14)) + +#define CTEMP_MASK 0xfff + +#define MCELSIUS(temp) ((temp) * 1000) +#define GEN3_FUSE_MASK 0xfff +#define GEN4_FUSE_MASK 0xfff + +#define TSC_MAX_NUM 5 + +struct rcar_gen3_thermal_priv; + +struct rcar_gen3_thermal_fuse_info { + u32 ptat[3]; + u32 thcode[3]; + u32 mask; +}; + +struct rcar_gen3_thermal_fuse_default { + u32 ptat[3]; + u32 thcodes[TSC_MAX_NUM][3]; +}; + +struct rcar_thermal_info { + int scale; + int adj_below; + int adj_above; + const struct rcar_gen3_thermal_fuse_info *fuses; + const struct rcar_gen3_thermal_fuse_default *fuse_defaults; +}; + +struct equation_set_coef { + int a; + int b; +}; + +struct rcar_gen3_thermal_tsc { + void __iomem *base; + /* Different coefficients are used depending on a threshold. */ + struct { + struct equation_set_coef below; + struct equation_set_coef above; + } coef; + int thcode[3]; +}; + +struct rcar_gen3_thermal_priv { + struct rcar_gen3_thermal_tsc tscs[TSC_MAX_NUM]; + unsigned int num_tscs; + int ptat[3]; +}; + +static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc, + u32 reg) +{ + return readl(tsc->base + reg); +} + +static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc, + u32 reg, u32 data) +{ + writel(data, tsc->base + reg); +} + +/* + * Linear approximation for temperature + * + * [temp] = ((thadj - [reg]) * a) / b + adj + * [reg] = thadj - ([temp] - adj) * b / a + * + * The constants a and b are calculated using two triplets of int values PTAT + * and THCODE. PTAT and THCODE can either be read from hardware or use hard + * coded values from the driver. The formula to calculate a and b are taken from + * the datasheet. Different calculations are needed for a and b depending on + * if the input variables ([temp] or [reg]) are above or below a threshold. The + * threshold is also calculated from PTAT and THCODE using formulas from the + * datasheet. + * + * The constant thadj is one of the THCODE values, which one to use depends on + * the threshold and input value. + * + * The constants adj is taken verbatim from the datasheet. Two values exists, + * which one to use depends on the input value and the calculated threshold. + * Furthermore different SoC models supported by the driver have different sets + * of values. The values for each model are stored in the device match data. + */ +static void rcar_gen3_thermal_tsc_coefs(struct udevice *dev, + struct rcar_gen3_thermal_tsc *tsc) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + + tsc->coef.below.a = info->scale * (priv->ptat[2] - priv->ptat[1]); + tsc->coef.above.a = info->scale * (priv->ptat[0] - priv->ptat[1]); + + tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]); + tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]); +} + +static int rcar_gen3_thermal_get_temp(struct udevice *dev, int *temp) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev->parent); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev->parent); + unsigned int tsc_id = dev_get_driver_data(dev); + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[tsc_id]); + const struct equation_set_coef *coef; + int adj, decicelsius, reg, thcode; + + /* Read register and convert to millidegree Celsius */ + reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; + + if (reg < tsc->thcode[1]) { + adj = info->adj_below; + coef = &tsc->coef.below; + thcode = tsc->thcode[2]; + } else { + adj = info->adj_above; + coef = &tsc->coef.above; + thcode = tsc->thcode[0]; + } + + /* + * The dividend can't be grown as it might overflow, instead shorten the + * divisor to convert to decidegree Celsius. If we convert after the + * division precision is lost as we will scale up from whole degrees + * Celsius. + */ + decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10); + + /* Guaranteed operating range is -40C to 125C. */ + + /* Reporting is done in millidegree Celsius */ + *temp = decicelsius * 100 + adj * 1000; + + return 0; +} + +static const struct dm_thermal_ops rcar_gen3_thermal_ops = { + .get_temp = rcar_gen3_thermal_get_temp, +}; + +static void rcar_gen3_thermal_fetch_fuses(struct udevice *dev) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + const struct rcar_gen3_thermal_fuse_info *fuses = info->fuses; + + /* + * Set the pseudo calibration points with fused values. + * PTAT is shared between all TSCs but only fused for the first + * TSC while THCODEs are fused for each TSC. + */ + priv->ptat[0] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[0]) + & fuses->mask; + priv->ptat[1] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[1]) + & fuses->mask; + priv->ptat[2] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[2]) + & fuses->mask; + + for (unsigned int i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]); + + tsc->thcode[0] = rcar_gen3_thermal_read(tsc, fuses->thcode[0]) + & fuses->mask; + tsc->thcode[1] = rcar_gen3_thermal_read(tsc, fuses->thcode[1]) + & fuses->mask; + tsc->thcode[2] = rcar_gen3_thermal_read(tsc, fuses->thcode[2]) + & fuses->mask; + } +} + +static bool rcar_gen3_thermal_read_fuses(struct udevice *dev) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + const struct rcar_gen3_thermal_fuse_default *fuse_defaults = info->fuse_defaults; + unsigned int i; + u32 thscp; + + /* If fuses are not set, fallback to pseudo values. */ + thscp = rcar_gen3_thermal_read(&(priv->tscs[0]), REG_GEN3_THSCP); + if (!info->fuses || + (thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) { + /* Default THCODE values in case FUSEs are not set. */ + priv->ptat[0] = fuse_defaults->ptat[0]; + priv->ptat[1] = fuse_defaults->ptat[1]; + priv->ptat[2] = fuse_defaults->ptat[2]; + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]); + + tsc->thcode[0] = fuse_defaults->thcodes[i][0]; + tsc->thcode[1] = fuse_defaults->thcodes[i][1]; + tsc->thcode[2] = fuse_defaults->thcodes[i][2]; + } + + return false; + } + + rcar_gen3_thermal_fetch_fuses(dev); + + return true; +} + +static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv, + struct rcar_gen3_thermal_tsc *tsc) +{ + u32 reg_val; + + reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR); + reg_val &= ~THCTR_PONM; + rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val); + + udelay(1000); + + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0); + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); + + reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR); + reg_val |= THCTR_THSST; + rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val); + + udelay(1000); +} + +static int rcar_gen3_thermal_probe(struct udevice *dev) +{ + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + unsigned int i; + + if (!rcar_gen3_thermal_read_fuses(dev)) + dev_dbg(dev, "No calibration values fused, fallback to driver values\n"); + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]); + + rcar_gen3_thermal_init(priv, tsc); + rcar_gen3_thermal_tsc_coefs(dev, tsc); + } + + return 0; +} + +static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen3 = { + .ptat = { REG_GEN3_PTAT1, REG_GEN3_PTAT2, REG_GEN3_PTAT3 }, + .thcode = { REG_GEN3_THCODE1, REG_GEN3_THCODE2, REG_GEN3_THCODE3 }, + .mask = GEN3_FUSE_MASK, +}; + +static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen4 = { + .ptat = { REG_GEN4_THSFMON16, REG_GEN4_THSFMON17, REG_GEN4_THSFMON15 }, + .thcode = { REG_GEN4_THSFMON01, REG_GEN4_THSFMON02, REG_GEN4_THSFMON00 }, + .mask = GEN4_FUSE_MASK, +}; + +static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_gen3 = { + .ptat = { 2631, 1509, 435 }, + .thcodes = { + { 3397, 2800, 2221 }, + { 3393, 2795, 2216 }, + { 3389, 2805, 2237 }, + { 3415, 2694, 2195 }, + { 3356, 2724, 2244 }, + }, +}; + +static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_v4h = { + .ptat = { 3274, 2164, 985 }, + .thcodes = { /* All four THS units share the same trimming */ + { 3218, 2617, 1980 }, + { 3218, 2617, 1980 }, + { 3218, 2617, 1980 }, + { 3218, 2617, 1980 }, + } +}; + +static const struct rcar_thermal_info rcar_m3w_thermal_info = { + .scale = 157, + .adj_below = -41, + .adj_above = 116, + .fuses = &rcar_gen3_thermal_fuse_info_gen3, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, +}; + +static const struct rcar_thermal_info rcar_gen3_thermal_info = { + .scale = 167, + .adj_below = -41, + .adj_above = 126, + .fuses = &rcar_gen3_thermal_fuse_info_gen3, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, +}; + +static const struct rcar_thermal_info rcar_gen4_thermal_info = { + .scale = 167, + .adj_below = -41, + .adj_above = 126, + .fuses = &rcar_gen3_thermal_fuse_info_gen4, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, +}; + +static const struct rcar_thermal_info rcar_v4h_thermal_info = { + .scale = 167, + .adj_below = -41, + .adj_above = 126, + .fuses = &rcar_gen3_thermal_fuse_info_gen4, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_v4h, +}; + +static const struct udevice_id rcar_gen3_thermal_ids[] = { + { + .compatible = "renesas,r8a774a1-thermal", + .data = (ulong)&rcar_m3w_thermal_info, + }, + { + .compatible = "renesas,r8a774b1-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a774e1-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a7795-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a7796-thermal", + .data = (ulong)&rcar_m3w_thermal_info, + }, + { + .compatible = "renesas,r8a77961-thermal", + .data = (ulong)&rcar_m3w_thermal_info, + }, + { + .compatible = "renesas,r8a77965-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a77980-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a779a0-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a779f0-thermal", + .data = (ulong)&rcar_gen4_thermal_info, + }, + { + .compatible = "renesas,r8a779g0-thermal", + .data = (ulong)&rcar_v4h_thermal_info, + }, + { + .compatible = "renesas,r8a779h0-thermal", + .data = (ulong)&rcar_gen4_thermal_info, + }, + { } +}; + +U_BOOT_DRIVER(thermal_rcar_gen3_tsc) = { + .name = "thermal-rcar-gen3-tsc", + .id = UCLASS_THERMAL, + .ops = &rcar_gen3_thermal_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static int rcar_gen3_thermal_bind(struct udevice *dev) +{ + /* + * We use dev_get_plat() here, because plat data are available + * in bind, while private data are not allocated yet. + */ + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + struct udevice *tdev; + struct driver *tdrv; + char name[32]; + void *addr; + int i, ret; + + tdrv = lists_driver_lookup_name("thermal-rcar-gen3-tsc"); + if (!tdrv) + return -ENOENT; + + for (i = 0; i < TSC_MAX_NUM; i++) { + addr = dev_read_addr_index_ptr(dev, i); + if (!addr) + break; + + priv->tscs[i].base = addr; + + tdev = NULL; + snprintf(name, sizeof(name), "thermal-rcar-gen3-tsc.%d", i); + ret = device_bind_with_driver_data(dev, tdrv, strdup(name), i, + dev_ofnode(dev), &tdev); + if (ret) + return ret; + } + + priv->num_tscs = i; + + return 0; +} + +U_BOOT_DRIVER(thermal_rcar_gen3) = { + .name = "thermal-rcar-gen3", + .id = UCLASS_NOP, + .of_match = rcar_gen3_thermal_ids, + .bind = rcar_gen3_thermal_bind, + .probe = rcar_gen3_thermal_probe, + .plat_auto = sizeof(struct rcar_gen3_thermal_priv), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/thermal/thermal_sandbox.c b/drivers/thermal/thermal_sandbox.c index 9af0d0247cb..2e1f1559e53 100644 --- a/drivers/thermal/thermal_sandbox.c +++ b/drivers/thermal/thermal_sandbox.c @@ -9,10 +9,10 @@ #include <dm.h> #include <thermal.h> -int sandbox_thermal_get_temp(struct udevice *dev, int *temp) +static int sandbox_thermal_get_temp(struct udevice *dev, int *temp) { /* Simply return 100 deg C */ - *temp = 100; + *temp = 100 * 1000; return 0; } diff --git a/drivers/thermal/ti-bandgap.c b/drivers/thermal/ti-bandgap.c index 0ea17a909dd..dc869f108e4 100644 --- a/drivers/thermal/ti-bandgap.c +++ b/drivers/thermal/ti-bandgap.c @@ -163,7 +163,7 @@ static int ti_bandgap_get_temp(struct udevice *dev, int *temp) struct ti_bandgap *bgp = dev_get_priv(dev); bgp->adc_val = 0x3ff & readl(bgp->base + CTRL_CORE_TEMP_SENSOR_MPU); - *temp = dra752_adc_to_temp[bgp->adc_val - DRA752_ADC_START_VALUE]; + *temp = dra752_adc_to_temp[bgp->adc_val - DRA752_ADC_START_VALUE] * 1000; return 0; } diff --git a/drivers/thermal/ti-lm74.c b/drivers/thermal/ti-lm74.c index 7d56f75df06..104c27429f4 100644 --- a/drivers/thermal/ti-lm74.c +++ b/drivers/thermal/ti-lm74.c @@ -28,7 +28,7 @@ static int ti_lm74_get_temp(struct udevice *dev, int *temp) raw = ((buf[0] << 8) + buf[1]) >> 3; - *temp = (((int)raw * 125) + 1000) / 2000; + *temp = (((int)raw * 125) + 1000) / 2; return 0; } @@ -44,7 +44,7 @@ static const struct udevice_id of_ti_lm74_match[] = { {}, }; -U_BOOT_DRIVER(ti_bandgap_thermal) = { +U_BOOT_DRIVER(ti_lm74_thermal) = { .name = "ti_lm74_thermal", .id = UCLASS_THERMAL, .ops = &ti_lm74_ops, diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index cb6fc0e7fda..f9511503b02 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -96,8 +96,8 @@ config ARM_TWD_TIMER config AST_TIMER bool "Aspeed ast2400/ast2500 timer support" - depends on TIMER - default y if ARCH_ASPEED + depends on TIMER && ARCH_ASPEED + default y help Select this to enable timer for Aspeed ast2400/ast2500 devices. This is a simple sys timer driver, it is compatible with lib/time.c, @@ -108,17 +108,10 @@ config AST_TIMER config AST_IBEX_TIMER bool "Aspeed ast2700 Ibex timer" - depends on TIMER + depends on TIMER && RISCV help Select this to enable a timer support for the Ibex RV32-based MCUs in AST2700. -config ATCPIT100_TIMER - bool "ATCPIT100 timer support" - depends on TIMER - help - Select this to enable a ATCPIT100 timer which will be embedded - in AE3XX, AE250 boards. - config ATMEL_PIT_TIMER bool "Atmel periodic interval timer support" depends on TIMER @@ -154,25 +147,18 @@ config SPL_ATMEL_TCB_TIMER config CADENCE_TTC_TIMER bool "Cadence TTC (Triple Timer Counter)" - depends on TIMER + depends on TIMER && ARCH_ZYNQMP_R5 help Enables support for the cadence ttc driver. This driver is present on Xilinx Zynq and ZynqMP SoCs. config DESIGNWARE_APB_TIMER bool "Designware APB Timer" - depends on TIMER + depends on TIMER && (ARCH_SOCFPGA || ARCH_ROCKCHIP) help Enables support for the Designware APB Timer driver. This timer is present on Altera SoCFPGA SoCs. -config FTTMR010_TIMER - bool "Faraday Technology timer support" - depends on TIMER - help - Select this to enable support for the timer found on - devices using Faraday Technology's IP. - config GXP_TIMER bool "HPE GXP Timer" depends on TIMER @@ -182,7 +168,7 @@ config GXP_TIMER config MPC83XX_TIMER bool "MPC83xx timer support" - depends on TIMER + depends on TIMER && PPC help Select this to enable support for the timer found on devices based on the MPC83xx family of SoCs. @@ -224,14 +210,14 @@ config NPCM_TIMER config OMAP_TIMER bool "Omap timer support" - depends on TIMER + depends on TIMER && (ARCH_OMAP2PLUS || ARCH_K3) help Select this to enable an timer for Omap devices. config ORION_TIMER bool "Orion timer support" - depends on TIMER - default y if ARCH_KIRKWOOD || (ARCH_MVEBU && ARMADA_32BIT) + depends on TIMER && (ARCH_KIRKWOOD || (ARCH_MVEBU && ARMADA_32BIT)) + default y select TIMER_EARLY if ARCH_MVEBU help Select this to enable an timer for Orion and Armada devices @@ -246,7 +232,7 @@ config RISCV_TIMER config ROCKCHIP_TIMER bool "Rockchip timer support" - depends on TIMER + depends on TIMER && ARCH_ROCKCHIP help Select this to enable support for the timer found on Rockchip devices. @@ -275,14 +261,14 @@ config SP804_TIMER config STM32_TIMER bool "STM32 timer support" - depends on TIMER + depends on TIMER && ARCH_STM32 help Select this to enable support for the timer found on STM32 devices. config TEGRA_TIMER bool "Tegra timer support" - depends on TIMER + depends on TIMER && ARCH_TEGRA select TIMER_EARLY help Select this to enable support for the timer found on @@ -326,7 +312,7 @@ config MTK_TIMER config MCHP_PIT64B_TIMER bool "Microchip 64-bit periodic interval timer support" - depends on TIMER + depends on TIMER && ARCH_AT91 help Select this to enable support for Microchip 64-bit periodic interval timer. diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index 21db0d317fe..a72e411fb2f 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_$(PHASE_)ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_$(PHASE_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o -obj-$(CONFIG_FTTMR010_TIMER) += fttmr010_timer.o obj-$(CONFIG_GXP_TIMER) += gxp-timer.o obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o diff --git a/drivers/timer/fttmr010_timer.c b/drivers/timer/fttmr010_timer.c deleted file mode 100644 index c41bbfc1d57..00000000000 --- a/drivers/timer/fttmr010_timer.c +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2009 Faraday Technology - * Po-Yu Chuang <ratbert@faraday-tech.com> - * - * 23/08/2022 Port to DM - */ -#include <dm.h> -#include <log.h> -#include <timer.h> -#include <asm/io.h> -#include <dm/ofnode.h> -#include <faraday/fttmr010.h> -#include <asm/global_data.h> - -#define TIMER_LOAD_VAL 0xffffffff - -struct fttmr010_timer_priv { - struct fttmr010 __iomem *regs; -}; - -static u64 fttmr010_timer_get_count(struct udevice *dev) -{ - struct fttmr010_timer_priv *priv = dev_get_priv(dev); - struct fttmr010 *tmr = priv->regs; - u32 now = TIMER_LOAD_VAL - readl(&tmr->timer3_counter); - - /* increment tbu if tbl has rolled over */ - if (now < gd->arch.tbl) - gd->arch.tbu++; - gd->arch.tbl = now; - - return ((u64)gd->arch.tbu << 32) | gd->arch.tbl; -} - -static int fttmr010_timer_probe(struct udevice *dev) -{ - struct fttmr010_timer_priv *priv = dev_get_priv(dev); - struct fttmr010 *tmr; - unsigned int cr; - - priv->regs = dev_read_addr_ptr(dev); - if (!priv->regs) - return -EINVAL; - tmr = priv->regs; - - debug("Faraday FTTMR010 timer revision 0x%08X\n", readl(&tmr->revision)); - - /* disable timers */ - writel(0, &tmr->cr); - - /* setup timer */ - writel(TIMER_LOAD_VAL, &tmr->timer3_load); - writel(TIMER_LOAD_VAL, &tmr->timer3_counter); - writel(0, &tmr->timer3_match1); - writel(0, &tmr->timer3_match2); - - /* we don't want timer to issue interrupts */ - writel(FTTMR010_TM3_MATCH1 | - FTTMR010_TM3_MATCH2 | - FTTMR010_TM3_OVERFLOW, - &tmr->interrupt_mask); - - cr = readl(&tmr->cr); - cr |= FTTMR010_TM3_CLOCK; /* use external clock */ - cr |= FTTMR010_TM3_ENABLE; - writel(cr, &tmr->cr); - - gd->arch.tbl = 0; - gd->arch.tbu = 0; - - return 0; -} - -static const struct timer_ops fttmr010_timer_ops = { - .get_count = fttmr010_timer_get_count, -}; - -static const struct udevice_id fttmr010_timer_ids[] = { - { .compatible = "faraday,fttmr010-timer" }, - {} -}; - -U_BOOT_DRIVER(fttmr010_timer) = { - .name = "fttmr010_timer", - .id = UCLASS_TIMER, - .of_match = fttmr010_timer_ids, - .priv_auto = sizeof(struct fttmr010_timer_priv), - .probe = fttmr010_timer_probe, - .ops = &fttmr010_timer_ops, -}; diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 01bc686d367..219ea606b50 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -75,24 +75,6 @@ config TPM_AUTH_SESSIONS TPM_LoadKey2 and TPM_GetPubKey are provided. Both features are available using the 'tpm' command, too. -config TPM_ST33ZP24_I2C - bool "STMicroelectronics ST33ZP24 I2C TPM" - depends on TPM_V1 && DM_I2C - ---help--- - This driver supports STMicroelectronics TPM devices connected on the I2C bus. - The usual tpm operations and the 'tpm' command can be used to talk - to the device using the standard TPM Interface Specification (TIS) - protocol - -config TPM_ST33ZP24_SPI - bool "STMicroelectronics ST33ZP24 SPI TPM" - depends on TPM_V1 && DM_SPI - ---help--- - This driver supports STMicroelectronics TPM devices connected on the SPI bus. - The usual tpm operations and the 'tpm' command can be used to talk - to the device using the standard TPM Interface Specification (TIS) - protocol - config TPM_FLUSH_RESOURCES bool "Enable TPM resource flushing support" depends on TPM_V1 diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 76e516dbbaf..b83ce703ec0 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -7,8 +7,6 @@ obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o sandbox_common.o -obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o -obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o obj-$(CONFIG_$(PHASE_)TPM2_CR50_I2C) += cr50_i2c.o obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index 5b2d5ccb146..14a94f8d4a8 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -388,7 +388,7 @@ static int cr50_i2c_recv(struct udevice *dev, u8 *buf, size_t buf_len) int status; int ret; - log_debug("%s: buf_len=%x\n", __func__, buf_len); + log_debug("%s: buf_len=%zx\n", __func__, buf_len); if (buf_len < TPM_HEADER_SIZE) return -E2BIG; @@ -465,7 +465,7 @@ static int cr50_i2c_send(struct udevice *dev, const u8 *buf, size_t len) ulong timeout; int ret; - log_debug("len=%x\n", len); + log_debug("len=%zx\n", len); timeout = timer_get_us() + TIMEOUT_LONG_US; do { ret = cr50_i2c_status(dev); diff --git a/drivers/tpm/tpm_tis_infineon.c b/drivers/tpm/tpm_tis_infineon.c index e2f6238cbc7..30f23f8610a 100644 --- a/drivers/tpm/tpm_tis_infineon.c +++ b/drivers/tpm/tpm_tis_infineon.c @@ -353,8 +353,7 @@ static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count) while (size < count) { burstcnt = tpm_tis_i2c_get_burstcount(dev); - /* burstcount < 0 -> tpm is busy */ - if (burstcnt < 0) + if (burstcnt == -EBUSY) return burstcnt; /* Limit received data to max left */ @@ -396,7 +395,7 @@ static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count) expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); if ((size_t)expected > count || (size_t)expected < TPM_HEADER_SIZE) { - debug("Error size=%x, expected=%x, count=%x\n", size, expected, + debug("Error size=%x, expected=%x, count=%zx\n", size, expected, count); return -ENOSPC; } @@ -429,7 +428,7 @@ static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len) int retry = 0; u8 sts = TPM_STS_GO; - debug("%s: len=%d\n", __func__, len); + debug("%s: len=%zd\n", __func__, len); if (len > TPM_DEV_BUFSIZE) return -E2BIG; /* Command is too long for our tpm, sorry */ @@ -449,8 +448,7 @@ static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len) burstcnt = tpm_tis_i2c_get_burstcount(dev); - /* burstcount < 0 -> tpm is busy */ - if (burstcnt < 0) + if (burstcnt == -EBUSY) return burstcnt; while (count < len) { diff --git a/drivers/tpm/tpm_tis_st33zp24_i2c.c b/drivers/tpm/tpm_tis_st33zp24_i2c.c deleted file mode 100644 index 1a265b28b22..00000000000 --- a/drivers/tpm/tpm_tis_st33zp24_i2c.c +++ /dev/null @@ -1,545 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * STMicroelectronics TPM ST33ZP24 I2C UBOOT driver - * - * Copyright (C) 2016, STMicroelectronics - All Rights Reserved - * Author(s): Christophe Ricard <christophe-h.ricard@st.com> for STMicroelectronics. - * - * Description: Device driver for ST33ZP24 I2C TPM TCG. - * - * This device driver implements the TPM interface as defined in - * the TCG TPM Interface Spec version 1.21, revision 1.0 and the - * STMicroelectronics Protocol Stack Specification version 1.2.0. - */ - -#include <dm.h> -#include <fdtdec.h> -#include <i2c.h> -#include <log.h> -#include <tpm-v1.h> -#include <errno.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <asm/unaligned.h> - -#include "tpm_tis.h" -#include "tpm_internal.h" - -#define TPM_ACCESS 0x0 -#define TPM_STS 0x18 -#define TPM_DATA_FIFO 0x24 - -#define LOCALITY0 0 - -#define TPM_DUMMY_BYTE 0xAA -#define TPM_ST33ZP24_I2C_SLAVE_ADDR 0x13 - -#define TPM_WRITE_DIRECTION 0x80 - -/* - * st33zp24_i2c_write8_reg - * Send byte to the TIS register according to the ST33ZP24 I2C protocol. - * @param: tpm_register, the tpm tis register where the data should be written - * @param: tpm_data, the tpm_data to write inside the tpm_register - * @param: tpm_size, The length of the data - * @return: Number of byte written successfully else an error code. - */ -static int st33zp24_i2c_write8_reg(struct udevice *dev, u8 tpm_register, - const u8 *tpm_data, size_t tpm_size) -{ - struct tpm_chip_priv *chip_priv = dev_get_uclass_priv(dev); - - chip_priv->buf[0] = tpm_register; - memcpy(chip_priv->buf + 1, tpm_data, tpm_size); - - return dm_i2c_write(dev, 0, chip_priv->buf, tpm_size + 1); -} - -/* -* st33zp24_i2c_read8_reg -* Recv byte from the TIS register according to the ST33ZP24 I2C protocol. -* @param: tpm_register, the tpm tis register where the data should be read -* @param: tpm_data, the TPM response -* @param: tpm_size, tpm TPM response size to read. -* @return: Number of byte read successfully else an error code. -*/ -static int st33zp24_i2c_read8_reg(struct udevice *dev, u8 tpm_register, - u8 *tpm_data, size_t tpm_size) -{ - int status; - u8 data; - - data = TPM_DUMMY_BYTE; - status = st33zp24_i2c_write8_reg(dev, tpm_register, &data, 1); - if (status < 0) - return status; - - return dm_i2c_read(dev, 0, tpm_data, tpm_size); -} - -/* - * st33zp24_i2c_write - * Send byte to the TIS register according to the ST33ZP24 I2C protocol. - * @param: phy_id, the phy description - * @param: tpm_register, the tpm tis register where the data should be written - * @param: tpm_data, the tpm_data to write inside the tpm_register - * @param: tpm_size, the length of the data - * @return: number of byte written successfully: should be one if success. - */ -static int st33zp24_i2c_write(struct udevice *dev, u8 tpm_register, - const u8 *tpm_data, size_t tpm_size) -{ - return st33zp24_i2c_write8_reg(dev, tpm_register | TPM_WRITE_DIRECTION, - tpm_data, tpm_size); -} - -/* - * st33zp24_i2c_read - * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. - * @param: phy_id, the phy description - * @param: tpm_register, the tpm tis register where the data should be read - * @param: tpm_data, the TPM response - * @param: tpm_size, tpm TPM response size to read. - * @return: number of byte read successfully: should be one if success. - */ -static int st33zp24_i2c_read(struct udevice *dev, u8 tpm_register, - u8 *tpm_data, size_t tpm_size) -{ - return st33zp24_i2c_read8_reg(dev, tpm_register, tpm_data, tpm_size); -} - -/* - * st33zp24_i2c_release_locality release the active locality - * @param: chip, the tpm chip description. - */ -static void st33zp24_i2c_release_locality(struct udevice *dev) -{ - u8 data = TPM_ACCESS_ACTIVE_LOCALITY; - - st33zp24_i2c_write(dev, TPM_ACCESS, &data, 1); -} - -/* - * st33zp24_i2c_check_locality if the locality is active - * @param: chip, the tpm chip description - * @return: the active locality or -EACCES. - */ -static int st33zp24_i2c_check_locality(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - u8 data; - u8 status; - - status = st33zp24_i2c_read(dev, TPM_ACCESS, &data, 1); - if (!status && (data & - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) - return chip->locality; - - return -EACCES; -} - -/* - * st33zp24_i2c_request_locality request the TPM locality - * @param: chip, the chip description - * @return: the active locality or negative value. - */ -static int st33zp24_i2c_request_locality(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - unsigned long start, stop; - long ret; - u8 data; - - if (st33zp24_i2c_check_locality(dev) == chip->locality) - return chip->locality; - - data = TPM_ACCESS_REQUEST_USE; - ret = st33zp24_i2c_write(dev, TPM_ACCESS, &data, 1); - if (ret < 0) - return ret; - - /* wait for locality activated */ - start = get_timer(0); - stop = chip->timeout_a; - do { - if (st33zp24_i2c_check_locality(dev) >= 0) - return chip->locality; - udelay(TPM_TIMEOUT_MS * 1000); - } while (get_timer(start) < stop); - - return -EACCES; -} - -/* - * st33zp24_i2c_status return the TPM_STS register - * @param: chip, the tpm chip description - * @return: the TPM_STS register value. - */ -static u8 st33zp24_i2c_status(struct udevice *dev) -{ - u8 data; - - st33zp24_i2c_read(dev, TPM_STS, &data, 1); - - return data; -} - -/* - * st33zp24_i2c_get_burstcount return the burstcount address 0x19 0x1A - * @param: chip, the chip description - * return: the burstcount or -TPM_DRIVER_ERR in case of error. - */ -static int st33zp24_i2c_get_burstcount(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - unsigned long start, stop; - int burstcnt, status; - u8 tpm_reg, temp; - - /* wait for burstcount */ - start = get_timer(0); - stop = chip->timeout_d; - do { - tpm_reg = TPM_STS + 1; - status = st33zp24_i2c_read(dev, tpm_reg, &temp, 1); - if (status < 0) - return -EBUSY; - - tpm_reg = TPM_STS + 2; - burstcnt = temp; - status = st33zp24_i2c_read(dev, tpm_reg, &temp, 1); - if (status < 0) - return -EBUSY; - - burstcnt |= temp << 8; - if (burstcnt) - return burstcnt; - udelay(TIS_SHORT_TIMEOUT_MS * 1000); - } while (get_timer(start) < stop); - - return -EBUSY; -} - -/* - * st33zp24_i2c_cancel, cancel the current command execution or - * set STS to COMMAND READY. - * @param: chip, tpm_chip description. - */ -static void st33zp24_i2c_cancel(struct udevice *dev) -{ - u8 data; - - data = TPM_STS_COMMAND_READY; - st33zp24_i2c_write(dev, TPM_STS, &data, 1); -} - -/* - * st33zp24_i2c_wait_for_stat wait for a TPM_STS value - * @param: chip, the tpm chip description - * @param: mask, the value mask to wait - * @param: timeout, the timeout - * @param: status, - * @return: the tpm status, 0 if success, -ETIME if timeout is reached. - */ -static int st33zp24_i2c_wait_for_stat(struct udevice *dev, u8 mask, - unsigned long timeout, int *status) -{ - unsigned long start, stop; - - /* Check current status */ - *status = st33zp24_i2c_status(dev); - if ((*status & mask) == mask) - return 0; - - start = get_timer(0); - stop = timeout; - do { - udelay(TPM_TIMEOUT_MS * 1000); - *status = st33zp24_i2c_status(dev); - if ((*status & mask) == mask) - return 0; - } while (get_timer(start) < stop); - - return -ETIME; -} - -/* - * st33zp24_i2c_recv_data receive data - * @param: chip, the tpm chip description - * @param: buf, the buffer where the data are received - * @param: count, the number of data to receive - * @return: the number of bytes read from TPM FIFO. - */ -static int st33zp24_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count) -{ - struct tpm_chip *chip = dev_get_priv(dev); - int size = 0, burstcnt, len, ret, status; - - while (size < count && - st33zp24_i2c_wait_for_stat(dev, TPM_STS_DATA_AVAIL | TPM_STS_VALID, - chip->timeout_c, &status) == 0) { - burstcnt = st33zp24_i2c_get_burstcount(dev); - if (burstcnt < 0) - return burstcnt; - len = min_t(int, burstcnt, count - size); - ret = st33zp24_i2c_read(dev, TPM_DATA_FIFO, buf + size, len); - if (ret < 0) - return ret; - - size += len; - } - - return size; -} - -/* - * st33zp24_i2c_recv received TPM response through TPM phy. - * @param: chip, tpm_chip description. - * @param: buf, the buffer to store data. - * @param: count, the number of bytes that can received (sizeof buf). - * @return: Returns zero in case of success else -EIO. - */ -static int st33zp24_i2c_recv(struct udevice *dev, u8 *buf, size_t count) -{ - struct tpm_chip *chip = dev_get_priv(dev); - int size; - unsigned int expected; - - if (!chip) - return -ENODEV; - - if (count < TPM_HEADER_SIZE) { - size = -EIO; - goto out; - } - - size = st33zp24_i2c_recv_data(dev, buf, TPM_HEADER_SIZE); - if (size < TPM_HEADER_SIZE) { - debug("TPM error, unable to read header\n"); - goto out; - } - - expected = get_unaligned_be32(buf + 2); - if (expected > count || expected < TPM_HEADER_SIZE) { - size = -EIO; - goto out; - } - - size += st33zp24_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); - if (size < expected) { - debug("TPM error, unable to read remaining bytes of result\n"); - size = -EIO; - goto out; - } - -out: - st33zp24_i2c_cancel(dev); - st33zp24_i2c_release_locality(dev); - - return size; -} - -/* - * st33zp24_i2c_send send TPM commands through TPM phy. - * @param: chip, tpm_chip description. - * @param: buf, the buffer to send. - * @param: len, the number of bytes to send. - * @return: Returns zero in case of success else the negative error code. - */ -static int st33zp24_i2c_send(struct udevice *dev, const u8 *buf, size_t len) -{ - struct tpm_chip *chip = dev_get_priv(dev); - u32 i, size; - int burstcnt, ret, status; - u8 data, tpm_stat; - - if (!chip) - return -ENODEV; - if (len < TPM_HEADER_SIZE) - return -EIO; - - ret = st33zp24_i2c_request_locality(dev); - if (ret < 0) - return ret; - - tpm_stat = st33zp24_i2c_status(dev); - if ((tpm_stat & TPM_STS_COMMAND_READY) == 0) { - st33zp24_i2c_cancel(dev); - if (st33zp24_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY, - chip->timeout_b, &status) < 0) { - ret = -ETIME; - goto out_err; - } - } - - for (i = 0; i < len - 1;) { - burstcnt = st33zp24_i2c_get_burstcount(dev); - if (burstcnt < 0) - return burstcnt; - - size = min_t(int, len - i - 1, burstcnt); - ret = st33zp24_i2c_write(dev, TPM_DATA_FIFO, buf + i, size); - if (ret < 0) - goto out_err; - - i += size; - } - - tpm_stat = st33zp24_i2c_status(dev); - if ((tpm_stat & TPM_STS_DATA_EXPECT) == 0) { - ret = -EIO; - goto out_err; - } - - ret = st33zp24_i2c_write(dev, TPM_DATA_FIFO, buf + len - 1, 1); - if (ret < 0) - goto out_err; - - tpm_stat = st33zp24_i2c_status(dev); - if ((tpm_stat & TPM_STS_DATA_EXPECT) != 0) { - ret = -EIO; - goto out_err; - } - - data = TPM_STS_GO; - ret = st33zp24_i2c_write(dev, TPM_STS, &data, 1); - if (ret < 0) - goto out_err; - - return len; - -out_err: - st33zp24_i2c_cancel(dev); - st33zp24_i2c_release_locality(dev); - - return ret; -} - -static int st33zp24_i2c_cleanup(struct udevice *dev) -{ - st33zp24_i2c_cancel(dev); - /* - * The TPM needs some time to clean up here, - * so we sleep rather than keeping the bus busy - */ - mdelay(2); - st33zp24_i2c_release_locality(dev); - - return 0; -} - -static int st33zp24_i2c_init(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - - chip->is_open = 1; - - /* Default timeouts - these could move to the device tree */ - chip->timeout_a = TIS_SHORT_TIMEOUT_MS; - chip->timeout_b = TIS_LONG_TIMEOUT_MS; - chip->timeout_c = TIS_SHORT_TIMEOUT_MS; - chip->timeout_d = TIS_SHORT_TIMEOUT_MS; - - chip->locality = LOCALITY0; - - /* - * A timeout query to TPM can be placed here. - * Standard timeout values are used so far - */ - - return 0; -} - -static int st33zp24_i2c_open(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - int rc; - - debug("%s: start\n", __func__); - if (chip->is_open) - return -EBUSY; - - rc = st33zp24_i2c_init(dev); - if (rc < 0) - chip->is_open = 0; - - return rc; -} - -static int st33zp24_i2c_close(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - - if (chip->is_open) { - st33zp24_i2c_release_locality(dev); - chip->is_open = 0; - chip->vend_dev = 0; - } - - return 0; -} - -static int st33zp24_i2c_get_desc(struct udevice *dev, char *buf, int size) -{ - struct tpm_chip *chip = dev_get_priv(dev); - - if (size < 50) - return -ENOSPC; - - return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)", - chip->is_open ? "open" : "closed", - dev->name, - chip->vend_dev >> 16); -} - -static const struct tpm_ops st33zp24_i2c_tpm_ops = { - .open = st33zp24_i2c_open, - .close = st33zp24_i2c_close, - .recv = st33zp24_i2c_recv, - .send = st33zp24_i2c_send, - .cleanup = st33zp24_i2c_cleanup, - .get_desc = st33zp24_i2c_get_desc, -}; - -static int st33zp24_i2c_probe(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - - /* Default timeouts */ - chip->timeout_a = TIS_SHORT_TIMEOUT_MS; - chip->timeout_b = TIS_LONG_TIMEOUT_MS; - chip->timeout_c = TIS_SHORT_TIMEOUT_MS; - chip->timeout_d = TIS_SHORT_TIMEOUT_MS; - - chip->locality = LOCALITY0; - - i2c_set_chip_offset_len(dev, 0); - - debug("ST33ZP24 I2C TPM from STMicroelectronics found\n"); - - return 0; -} - -static int st33zp24_i2c_remove(struct udevice *dev) -{ - st33zp24_i2c_release_locality(dev); - - return 0; -} - -static const struct udevice_id st33zp24_i2c_ids[] = { - { .compatible = "st,st33zp24-i2c" }, - { } -}; - -U_BOOT_DRIVER(st33zp24_i2c) = { - .name = "st33zp24-i2c", - .id = UCLASS_TPM, - .of_match = of_match_ptr(st33zp24_i2c_ids), - .probe = st33zp24_i2c_probe, - .remove = st33zp24_i2c_remove, - .ops = &st33zp24_i2c_tpm_ops, - .priv_auto = sizeof(struct tpm_chip), -}; diff --git a/drivers/tpm/tpm_tis_st33zp24_spi.c b/drivers/tpm/tpm_tis_st33zp24_spi.c deleted file mode 100644 index 2cf690328d8..00000000000 --- a/drivers/tpm/tpm_tis_st33zp24_spi.c +++ /dev/null @@ -1,674 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * STMicroelectronics TPM ST33ZP24 SPI UBOOT driver - * - * Copyright (C) 2016, STMicroelectronics - All Rights Reserved - * Author(s): Christophe Ricard <christophe-h.ricard@st.com> for STMicroelectronics. - * - * Description: Device driver for ST33ZP24 SPI TPM TCG. - * - * This device driver implements the TPM interface as defined in - * the TCG TPM Interface Spec version 1.21, revision 1.0 and the - * STMicroelectronics Protocol Stack Specification version 1.2.0. - */ - -#include <dm.h> -#include <fdtdec.h> -#include <log.h> -#include <spi.h> -#include <tpm-v1.h> -#include <errno.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <asm/unaligned.h> -#include <linux/compat.h> - -#include "tpm_tis.h" -#include "tpm_internal.h" - -#define TPM_ACCESS 0x0 -#define TPM_STS 0x18 -#define TPM_DATA_FIFO 0x24 - -#define LOCALITY0 0 - -#define TPM_DATA_FIFO 0x24 -#define TPM_INTF_CAPABILITY 0x14 - -#define TPM_DUMMY_BYTE 0x00 -#define TPM_WRITE_DIRECTION 0x80 - -#define MAX_SPI_LATENCY 15 -#define LOCALITY0 0 - -#define ST33ZP24_OK 0x5A -#define ST33ZP24_UNDEFINED_ERR 0x80 -#define ST33ZP24_BADLOCALITY 0x81 -#define ST33ZP24_TISREGISTER_UKNOWN 0x82 -#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83 -#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84 -#define ST33ZP24_BAD_COMMAND_ORDER 0x85 -#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86 -#define ST33ZP24_TPM_FIFO_OVERFLOW 0x89 -#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A -#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B -#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90 -#define ST33ZP24_DUMMY_BYTES 0x00 - -/* - * TPM command can be up to 2048 byte, A TPM response can be up to - * 1024 byte. - * Between command and response, there are latency byte (up to 15 - * usually on st33zp24 2 are enough). - * - * Overall when sending a command and expecting an answer we need if - * worst case: - * 2048 (for the TPM command) + 1024 (for the TPM answer). We need - * some latency byte before the answer is available (max 15). - * We have 2048 + 1024 + 15. - */ -#define ST33ZP24_SPI_BUFFER_SIZE (TPM_BUFSIZE + (TPM_BUFSIZE / 2) +\ - MAX_SPI_LATENCY) - -struct st33zp24_spi_phy { - int latency; - - u8 tx_buf[ST33ZP24_SPI_BUFFER_SIZE]; - u8 rx_buf[ST33ZP24_SPI_BUFFER_SIZE]; -}; - -static int st33zp24_spi_status_to_errno(u8 code) -{ - switch (code) { - case ST33ZP24_OK: - return 0; - case ST33ZP24_UNDEFINED_ERR: - case ST33ZP24_BADLOCALITY: - case ST33ZP24_TISREGISTER_UKNOWN: - case ST33ZP24_LOCALITY_NOT_ACTIVATED: - case ST33ZP24_HASH_END_BEFORE_HASH_START: - case ST33ZP24_BAD_COMMAND_ORDER: - case ST33ZP24_UNEXPECTED_READ_FIFO: - case ST33ZP24_UNEXPECTED_WRITE_FIFO: - case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END: - return -EPROTO; - case ST33ZP24_INCORECT_RECEIVED_LENGTH: - case ST33ZP24_TPM_FIFO_OVERFLOW: - return -EMSGSIZE; - case ST33ZP24_DUMMY_BYTES: - return -ENOSYS; - } - return code; -} - -/* - * st33zp24_spi_send - * Send byte to TPM register according to the ST33ZP24 SPI protocol. - * @param: tpm, the chip description - * @param: tpm_register, the tpm tis register where the data should be written - * @param: tpm_data, the tpm_data to write inside the tpm_register - * @param: tpm_size, The length of the data - * @return: should be zero if success else a negative error code. - */ -static int st33zp24_spi_write(struct udevice *dev, u8 tpm_register, - const u8 *tpm_data, size_t tpm_size) -{ - int total_length = 0, ret; - struct spi_slave *slave = dev_get_parent_priv(dev); - struct st33zp24_spi_phy *phy = dev_get_plat(dev); - - u8 *tx_buf = (u8 *)phy->tx_buf; - u8 *rx_buf = phy->rx_buf; - - tx_buf[total_length++] = TPM_WRITE_DIRECTION | LOCALITY0; - tx_buf[total_length++] = tpm_register; - - if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) { - tx_buf[total_length++] = tpm_size >> 8; - tx_buf[total_length++] = tpm_size; - } - memcpy(tx_buf + total_length, tpm_data, tpm_size); - total_length += tpm_size; - - memset(tx_buf + total_length, TPM_DUMMY_BYTE, phy->latency); - - total_length += phy->latency; - - ret = spi_claim_bus(slave); - if (ret < 0) - return ret; - - ret = spi_xfer(slave, total_length * 8, tx_buf, rx_buf, - SPI_XFER_BEGIN | SPI_XFER_END); - if (ret < 0) - return ret; - - spi_release_bus(slave); - - if (ret == 0) - ret = rx_buf[total_length - 1]; - - return st33zp24_spi_status_to_errno(ret); -} - -/* - * spi_st33zp24_spi_read8_reg - * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. - * @param: tpm, the chip description - * @param: tpm_loc, the locality to read register from - * @param: tpm_register, the tpm tis register where the data should be read - * @param: tpm_data, the TPM response - * @param: tpm_size, tpm TPM response size to read. - * @return: should be zero if success else a negative error code. - */ -static u8 st33zp24_spi_read8_reg(struct udevice *dev, u8 tpm_register, - u8 *tpm_data, size_t tpm_size) -{ - int total_length = 0, ret; - struct spi_slave *slave = dev_get_parent_priv(dev); - struct st33zp24_spi_phy *phy = dev_get_plat(dev); - - u8 *tx_buf = (u8 *)phy->tx_buf; - u8 *rx_buf = phy->rx_buf; - - /* Pre-Header */ - tx_buf[total_length++] = LOCALITY0; - tx_buf[total_length++] = tpm_register; - - memset(&tx_buf[total_length], TPM_DUMMY_BYTE, - phy->latency + tpm_size); - total_length += phy->latency + tpm_size; - - ret = spi_claim_bus(slave); - if (ret < 0) - return 0; - - ret = spi_xfer(slave, total_length * 8, tx_buf, rx_buf, - SPI_XFER_BEGIN | SPI_XFER_END); - if (ret < 0) - return 0; - - spi_release_bus(slave); - - if (tpm_size > 0 && ret == 0) { - ret = rx_buf[total_length - tpm_size - 1]; - memcpy(tpm_data, rx_buf + total_length - tpm_size, tpm_size); - } - return ret; -} - -/* - * st33zp24_spi_recv - * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. - * @param: phy_id, the phy description - * @param: tpm_register, the tpm tis register where the data should be read - * @param: tpm_data, the TPM response - * @param: tpm_size, tpm TPM response size to read. - * @return: number of byte read successfully: should be one if success. - */ -static int st33zp24_spi_read(struct udevice *dev, u8 tpm_register, - u8 *tpm_data, size_t tpm_size) -{ - int ret; - - ret = st33zp24_spi_read8_reg(dev, tpm_register, tpm_data, tpm_size); - if (!st33zp24_spi_status_to_errno(ret)) - return tpm_size; - - return ret; -} - -static int st33zp24_spi_evaluate_latency(struct udevice *dev) -{ - int latency = 1, status = 0; - u8 data = 0; - struct st33zp24_spi_phy *phy = dev_get_plat(dev); - - while (!status && latency < MAX_SPI_LATENCY) { - phy->latency = latency; - status = st33zp24_spi_read8_reg(dev, TPM_INTF_CAPABILITY, - &data, 1); - latency++; - } - if (status < 0) - return status; - if (latency == MAX_SPI_LATENCY) - return -ENODEV; - - return latency - 1; -} - -/* - * st33zp24_spi_release_locality release the active locality - * @param: chip, the tpm chip description. - */ -static void st33zp24_spi_release_locality(struct udevice *dev) -{ - u8 data = TPM_ACCESS_ACTIVE_LOCALITY; - - st33zp24_spi_write(dev, TPM_ACCESS, &data, 1); -} - -/* - * st33zp24_spi_check_locality if the locality is active - * @param: chip, the tpm chip description - * @return: the active locality or -EACCES. - */ -static int st33zp24_spi_check_locality(struct udevice *dev) -{ - u8 data; - u8 status; - struct tpm_chip *chip = dev_get_priv(dev); - - status = st33zp24_spi_read(dev, TPM_ACCESS, &data, 1); - if (status && (data & - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) - return chip->locality; - - return -EACCES; -} - -/* - * st33zp24_spi_request_locality request the TPM locality - * @param: chip, the chip description - * @return: the active locality or negative value. - */ -static int st33zp24_spi_request_locality(struct udevice *dev) -{ - unsigned long start, stop; - long ret; - u8 data; - struct tpm_chip *chip = dev_get_priv(dev); - - if (st33zp24_spi_check_locality(dev) == chip->locality) - return chip->locality; - - data = TPM_ACCESS_REQUEST_USE; - ret = st33zp24_spi_write(dev, TPM_ACCESS, &data, 1); - if (ret < 0) - return ret; - - /* wait for locality activated */ - start = get_timer(0); - stop = chip->timeout_a; - do { - if (st33zp24_spi_check_locality(dev) >= 0) - return chip->locality; - udelay(TPM_TIMEOUT_MS * 1000); - } while (get_timer(start) < stop); - - return -EACCES; -} - -/* - * st33zp24_spi_status return the TPM_STS register - * @param: chip, the tpm chip description - * @return: the TPM_STS register value. - */ -static u8 st33zp24_spi_status(struct udevice *dev) -{ - u8 data; - - st33zp24_spi_read(dev, TPM_STS, &data, 1); - return data; -} - -/* - * st33zp24_spi_get_burstcount return the burstcount address 0x19 0x1A - * @param: chip, the chip description - * return: the burstcount or -TPM_DRIVER_ERR in case of error. - */ -static int st33zp24_spi_get_burstcount(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - unsigned long start, stop; - int burstcnt, status; - u8 tpm_reg, temp; - - /* wait for burstcount */ - start = get_timer(0); - stop = chip->timeout_d; - do { - tpm_reg = TPM_STS + 1; - status = st33zp24_spi_read(dev, tpm_reg, &temp, 1); - if (status < 0) - return -EBUSY; - - tpm_reg = TPM_STS + 2; - burstcnt = temp; - status = st33zp24_spi_read(dev, tpm_reg, &temp, 1); - if (status < 0) - return -EBUSY; - - burstcnt |= temp << 8; - if (burstcnt) - return burstcnt; - udelay(TIS_SHORT_TIMEOUT_MS * 1000); - } while (get_timer(start) < stop); - - return -EBUSY; -} - -/* - * st33zp24_spi_cancel, cancel the current command execution or - * set STS to COMMAND READY. - * @param: chip, tpm_chip description. - */ -static void st33zp24_spi_cancel(struct udevice *dev) -{ - u8 data; - - data = TPM_STS_COMMAND_READY; - st33zp24_spi_write(dev, TPM_STS, &data, 1); -} - -/* - * st33zp24_spi_wait_for_stat wait for a TPM_STS value - * @param: chip, the tpm chip description - * @param: mask, the value mask to wait - * @param: timeout, the timeout - * @param: status, - * @return: the tpm status, 0 if success, -ETIME if timeout is reached. - */ -static int st33zp24_spi_wait_for_stat(struct udevice *dev, u8 mask, - unsigned long timeout, int *status) -{ - unsigned long start, stop; - - /* Check current status */ - *status = st33zp24_spi_status(dev); - if ((*status & mask) == mask) - return 0; - - start = get_timer(0); - stop = timeout; - do { - udelay(TPM_TIMEOUT_MS * 1000); - *status = st33zp24_spi_status(dev); - if ((*status & mask) == mask) - return 0; - } while (get_timer(start) < stop); - - return -ETIME; -} - -/* - * st33zp24_spi_recv_data receive data - * @param: chip, the tpm chip description - * @param: buf, the buffer where the data are received - * @param: count, the number of data to receive - * @return: the number of bytes read from TPM FIFO. - */ -static int st33zp24_spi_recv_data(struct udevice *dev, u8 *buf, size_t count) -{ - struct tpm_chip *chip = dev_get_priv(dev); - int size = 0, burstcnt, len, ret, status; - - while (size < count && - st33zp24_spi_wait_for_stat(dev, TPM_STS_DATA_AVAIL | TPM_STS_VALID, - chip->timeout_c, &status) == 0) { - burstcnt = st33zp24_spi_get_burstcount(dev); - if (burstcnt < 0) - return burstcnt; - len = min_t(int, burstcnt, count - size); - ret = st33zp24_spi_read(dev, TPM_DATA_FIFO, buf + size, len); - if (ret < 0) - return ret; - - size += len; - } - return size; -} - -/* - * st33zp24_spi_recv received TPM response through TPM phy. - * @param: chip, tpm_chip description. - * @param: buf, the buffer to store data. - * @param: count, the number of bytes that can received (sizeof buf). - * @return: Returns zero in case of success else -EIO. - */ -static int st33zp24_spi_recv(struct udevice *dev, u8 *buf, size_t count) -{ - struct tpm_chip *chip = dev_get_priv(dev); - int size; - unsigned int expected; - - if (!chip) - return -ENODEV; - - if (count < TPM_HEADER_SIZE) { - size = -EIO; - goto out; - } - - size = st33zp24_spi_recv_data(dev, buf, TPM_HEADER_SIZE); - if (size < TPM_HEADER_SIZE) { - debug("TPM error, unable to read header\n"); - goto out; - } - - expected = get_unaligned_be32(buf + 2); - if (expected > count || expected < TPM_HEADER_SIZE) { - size = -EIO; - goto out; - } - - size += st33zp24_spi_recv_data(dev, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); - if (size < expected) { - debug("TPM error, unable to read remaining bytes of result\n"); - size = -EIO; - goto out; - } - -out: - st33zp24_spi_cancel(dev); - st33zp24_spi_release_locality(dev); - - return size; -} - -/* - * st33zp24_spi_send send TPM commands through TPM phy. - * @param: chip, tpm_chip description. - * @param: buf, the buffer to send. - * @param: len, the number of bytes to send. - * @return: Returns zero in case of success else the negative error code. - */ -static int st33zp24_spi_send(struct udevice *dev, const u8 *buf, size_t len) -{ - struct tpm_chip *chip = dev_get_priv(dev); - u32 i, size; - int burstcnt, ret, status; - u8 data, tpm_stat; - - if (!chip) - return -ENODEV; - if (len < TPM_HEADER_SIZE) - return -EIO; - - ret = st33zp24_spi_request_locality(dev); - if (ret < 0) - return ret; - - tpm_stat = st33zp24_spi_status(dev); - if ((tpm_stat & TPM_STS_COMMAND_READY) == 0) { - st33zp24_spi_cancel(dev); - if (st33zp24_spi_wait_for_stat(dev, TPM_STS_COMMAND_READY, - chip->timeout_b, &status) < 0) { - ret = -ETIME; - goto out_err; - } - } - - for (i = 0; i < len - 1;) { - burstcnt = st33zp24_spi_get_burstcount(dev); - if (burstcnt < 0) - return burstcnt; - - size = min_t(int, len - i - 1, burstcnt); - ret = st33zp24_spi_write(dev, TPM_DATA_FIFO, buf + i, size); - if (ret < 0) - goto out_err; - - i += size; - } - - tpm_stat = st33zp24_spi_status(dev); - if ((tpm_stat & TPM_STS_DATA_EXPECT) == 0) { - ret = -EIO; - goto out_err; - } - - ret = st33zp24_spi_write(dev, TPM_DATA_FIFO, buf + len - 1, 1); - if (ret < 0) - goto out_err; - - tpm_stat = st33zp24_spi_status(dev); - if ((tpm_stat & TPM_STS_DATA_EXPECT) != 0) { - ret = -EIO; - goto out_err; - } - - data = TPM_STS_GO; - ret = st33zp24_spi_write(dev, TPM_STS, &data, 1); - if (ret < 0) - goto out_err; - - return len; - -out_err: - st33zp24_spi_cancel(dev); - st33zp24_spi_release_locality(dev); - - return ret; -} - -static int st33zp24_spi_cleanup(struct udevice *dev) -{ - st33zp24_spi_cancel(dev); - /* - * The TPM needs some time to clean up here, - * so we sleep rather than keeping the bus busy - */ - mdelay(2); - st33zp24_spi_release_locality(dev); - - return 0; -} - -static int st33zp24_spi_init(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - struct st33zp24_spi_phy *phy = dev_get_plat(dev); - - chip->is_open = 1; - - /* Default timeouts - these could move to the device tree */ - chip->timeout_a = TIS_SHORT_TIMEOUT_MS; - chip->timeout_b = TIS_LONG_TIMEOUT_MS; - chip->timeout_c = TIS_SHORT_TIMEOUT_MS; - chip->timeout_d = TIS_SHORT_TIMEOUT_MS; - - chip->locality = LOCALITY0; - - phy->latency = st33zp24_spi_evaluate_latency(dev); - if (phy->latency <= 0) - return -ENODEV; - - /* - * A timeout query to TPM can be placed here. - * Standard timeout values are used so far - */ - - return 0; -} - -static int st33zp24_spi_open(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - int rc; - - debug("%s: start\n", __func__); - if (chip->is_open) - return -EBUSY; - - rc = st33zp24_spi_init(dev); - if (rc < 0) - chip->is_open = 0; - - return rc; -} - -static int st33zp24_spi_close(struct udevice *dev) -{ - struct tpm_chip *chip = dev_get_priv(dev); - - if (chip->is_open) { - st33zp24_spi_release_locality(dev); - chip->is_open = 0; - chip->vend_dev = 0; - } - - return 0; -} - -static int st33zp24_spi_get_desc(struct udevice *dev, char *buf, int size) -{ - struct tpm_chip *chip = dev_get_priv(dev); - - if (size < 50) - return -ENOSPC; - - return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)", - chip->is_open ? "open" : "closed", - dev->name, - chip->vend_dev >> 16); -} - -const struct tpm_ops st33zp24_spi_tpm_ops = { - .open = st33zp24_spi_open, - .close = st33zp24_spi_close, - .recv = st33zp24_spi_recv, - .send = st33zp24_spi_send, - .cleanup = st33zp24_spi_cleanup, - .get_desc = st33zp24_spi_get_desc, -}; - -static int st33zp24_spi_probe(struct udevice *dev) -{ - struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev); - - uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS; - uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS; - uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS; - uc_priv->retry_time_ms = TPM_TIMEOUT_MS; - - debug("ST33ZP24 SPI TPM from STMicroelectronics found\n"); - - return 0; -} - -static int st33zp24_spi_remove(struct udevice *dev) -{ - st33zp24_spi_release_locality(dev); - - return 0; -} - -static const struct udevice_id st33zp24_spi_ids[] = { - { .compatible = "st,st33zp24-spi" }, - { } -}; - -U_BOOT_DRIVER(st33zp24_spi_spi) = { - .name = "st33zp24-spi", - .id = UCLASS_TPM, - .of_match = of_match_ptr(st33zp24_spi_ids), - .probe = st33zp24_spi_probe, - .remove = st33zp24_spi_remove, - .ops = &st33zp24_spi_tpm_ops, - .priv_auto = sizeof(struct tpm_chip), - .plat_auto = sizeof(struct st33zp24_spi_phy), -}; diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c index 1c5ed538370..896dda2de4e 100644 --- a/drivers/ufs/ufs-amd-versal2.c +++ b/drivers/ufs/ufs-amd-versal2.c @@ -26,6 +26,10 @@ #define MPHY_FAST_RX_AFE_CAL BIT(2) #define MPHY_FW_CALIB_CFG_VAL BIT(8) +#define MPHY_RX_OVRD_EN BIT(3) +#define MPHY_RX_OVRD_VAL BIT(2) +#define MPHY_RX_ACK_MASK BIT(0) + #define TX_RX_CFG_RDY_MASK GENMASK(3, 0) #define TIMEOUT_MICROSEC 1000000L @@ -422,10 +426,118 @@ static int ufs_versal2_link_startup_notify(struct ufs_hba *hba, return ret; } +static int ufs_versal2_phy_ratesel(struct ufs_hba *hba, u32 activelanes, u32 rx_req) +{ + u32 time_left, reg, lane; + int ret; + + for (lane = 0; lane < activelanes; lane++) { + time_left = TIMEOUT_MICROSEC; + ret = ufs_versal2_phy_reg_read(hba, RX_OVRD_IN_1(lane), ®); + if (ret) + return ret; + + reg |= MPHY_RX_OVRD_EN; + if (rx_req) + reg |= MPHY_RX_OVRD_VAL; + else + reg &= ~MPHY_RX_OVRD_VAL; + + ret = ufs_versal2_phy_reg_write(hba, RX_OVRD_IN_1(lane), reg); + if (ret) + return ret; + + do { + ret = ufs_versal2_phy_reg_read(hba, RX_PCS_OUT(lane), ®); + if (ret) + return ret; + + reg &= MPHY_RX_ACK_MASK; + if (reg == rx_req) + break; + + time_left--; + mdelay(5); + } while (time_left); + + if (!time_left) { + dev_err(hba->dev, "Invalid Rx Ack value.\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int ufs_get_max_pwr_mode(struct ufs_hba *hba, + struct ufs_pwr_mode_info *max_pwr_info) +{ + struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); + u32 lane, reg, rate = 0; + int ret = 0; + + /* If it is not a calibrated part, switch PWRMODE to SLOW_MODE */ + if (!priv->attcompval0 && !priv->attcompval1 && + !priv->ctlecompval0 && !priv->ctlecompval1) { + max_pwr_info->info.pwr_rx = SLOWAUTO_MODE; + max_pwr_info->info.pwr_tx = SLOWAUTO_MODE; + max_pwr_info->info.gear_rx = UFS_PWM_G1; + max_pwr_info->info.gear_tx = UFS_PWM_G1; + max_pwr_info->info.lane_tx = 1; + max_pwr_info->info.lane_rx = 1; + max_pwr_info->info.hs_rate = 0; + return 0; + } + + if (max_pwr_info->info.pwr_rx == SLOWAUTO_MODE || + max_pwr_info->info.pwr_tx == SLOWAUTO_MODE) + return 0; + + if (max_pwr_info->info.hs_rate == PA_HS_MODE_B) + rate = 1; + + /* Select the rate */ + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(CBRATESEL), rate); + if (ret) + return ret; + + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 1); + if (ret) + return ret; + + ret = ufs_versal2_phy_ratesel(hba, max_pwr_info->info.lane_tx, 1); + if (ret) + return ret; + + ret = ufs_versal2_phy_ratesel(hba, max_pwr_info->info.lane_tx, 0); + if (ret) + return ret; + + /* Remove rx_req override */ + for (lane = 0; lane < max_pwr_info->info.lane_tx; lane++) { + ret = ufs_versal2_phy_reg_read(hba, RX_OVRD_IN_1(lane), ®); + if (ret) + return ret; + + reg &= ~MPHY_RX_OVRD_EN; + ret = ufs_versal2_phy_reg_write(hba, RX_OVRD_IN_1(lane), reg); + if (ret) + return ret; + } + + if (max_pwr_info->info.lane_tx == UFS_LANE_2 && + max_pwr_info->info.lane_rx == UFS_LANE_2) + ret = ufshcd_dme_configure_adapt(hba, max_pwr_info->info.gear_tx, + PA_INITIAL_ADAPT); + + return 0; +} + static struct ufs_hba_ops ufs_versal2_hba_ops = { .init = ufs_versal2_init, .link_startup_notify = ufs_versal2_link_startup_notify, .hce_enable_notify = ufs_versal2_hce_enable_notify, + .get_max_pwr_mode = ufs_get_max_pwr_mode, }; static int ufs_versal2_probe(struct udevice *dev) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 91f6ad3bfef..57e6e8c013b 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -226,6 +226,21 @@ static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) return 0; } +int ufshcd_dme_configure_adapt(struct ufs_hba *hba, + int agreed_gear, + int adapt_val) +{ + int ret; + + if (agreed_gear < UFS_HS_G4) + adapt_val = PA_NO_ADAPT; + + ret = ufshcd_dme_set(hba, + UIC_ARG_MIB(PA_TXHSADAPTTYPE), + adapt_val); + return ret; +} + /** * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET * diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 53137fae3a8..0337ac5996b 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -428,6 +428,9 @@ enum uic_link_state { #define ATTR_SET_NOR 0 /* NORMAL */ #define ATTR_SET_ST 1 /* STATIC */ +int ufshcd_dme_configure_adapt(struct ufs_hba *hba, + int agreed_gear, + int adapt_val); int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, u32 mib_val, u8 peer); int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, diff --git a/drivers/ufs/ufshcd-dwc.h b/drivers/ufs/ufshcd-dwc.h index fc1bcca8ccb..f7d27736f44 100644 --- a/drivers/ufs/ufshcd-dwc.h +++ b/drivers/ufs/ufshcd-dwc.h @@ -17,6 +17,7 @@ #define CBREFCLKCTRL2 0x8132 #define CBCRCTRL 0x811F #define CBC10DIRECTCONF2 0x810E +#define CBRATESEL 0x8114 #define CBCREGADDRLSB 0x8116 #define CBCREGADDRMSB 0x8117 #define CBCREGWRLSB 0x8118 @@ -32,6 +33,8 @@ #define MRX_FSM_STATE 0xC1 /* M-PHY registers */ +#define RX_OVRD_IN_1(n) (0x3006 + ((n) * 0x100)) +#define RX_PCS_OUT(n) (0x300F + ((n) * 0x100)) #define FAST_FLAGS(n) (0x401C + ((n) * 0x100)) #define RX_AFE_ATT_IDAC(n) (0x4000 + ((n) * 0x100)) #define RX_AFE_CTLE_IDAC(n) (0x4001 + ((n) * 0x100)) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 682a6910655..744dfa90463 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -17,6 +17,7 @@ comment "Platform Glue Driver Support" config USB_DWC3_OMAP bool "Texas Instruments OMAP5 and similar Platforms" + depends on ARCH_OMAP2PLUS help Some platforms from Texas Instruments like OMAP5, DRA7xxx and AM437x use this IP for USB2/3 functionality. @@ -39,14 +40,14 @@ config SPL_USB_DWC3_GENERIC config SPL_USB_DWC3_AM62 bool "TI AM62 USB wrapper" - depends on SPL_DM_USB && SPL_USB_DWC3_GENERIC && SPL_SYSCON + depends on SPL_DM_USB && SPL_USB_DWC3_GENERIC && SPL_SYSCON && ARCH_K3 help Select this for TI AM62 Platforms. This wrapper supports Host and Peripheral operation modes. config USB_DWC3_AM62 bool "TI AM62 USB wrapper" - depends on DM_USB && USB_DWC3_GENERIC && SYSCON + depends on DM_USB && USB_DWC3_GENERIC && SYSCON && ARCH_K3 help Select this for TI AM62 Platforms. This wrapper supports Host and Peripheral operation modes. @@ -80,7 +81,7 @@ config USB_DWC3_UNIPHIER config USB_DWC3_LAYERSCAPE bool "Freescale Layerscape platform support" depends on DM_USB && USB_DWC3 - depends on !USB_XHCI_FSL + depends on !USB_XHCI_FSL && ARM help Select this for Freescale Layerscape Platforms. @@ -99,12 +100,14 @@ menu "PHY Subsystem" config USB_DWC3_PHY_OMAP bool "TI OMAP SoC series USB DRD PHY driver" + depends on ARCH_OMAP2PLUS help Enable single driver for both USB2 PHY programming and USB3 PHY programming for TI SoCs. config USB_DWC3_PHY_SAMSUNG bool "Exynos5 SoC series USB DRD PHY driver" + depends on ARCH_EXYNOS help Enable USB DRD PHY support for Exynos 5 SoC series. This driver provides PHY interface for USB 3.0 DRD controller diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c656cbe25ce..680756532f0 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -799,10 +799,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (status == DWC3_TRBSTS_SETUP_PENDING) { dev_dbg(dwc->dev, "Setup Pending received"); - - if (r) - dwc3_gadget_giveback(ep0, r, -ECONNRESET); - + dwc3_gadget_giveback(ep0, r, -ECONNRESET); return; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 0121f9872ae..e845e46e0b7 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -93,16 +93,12 @@ config USB_GADGET_PRODUCT_NUM config USB_GADGET_ATMEL_USBA bool "Atmel USBA" + depends on ARCH_AT91 select USB_GADGET_DUALSPEED help USBA is the integrated high-speed USB Device controller on the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. -config USB_GADGET_BCM_UDC_OTG_PHY - bool "Broadcom UDC OTG PHY" - help - Enable the Broadcom UDC OTG physical device interface. - config USB_GADGET_AT91 bool "Atmel AT91 USB Gadget Controller" depends on ARCH_AT91 @@ -156,12 +152,6 @@ config CI_UDC Say Y here to enable device controller functionality of the ChipIdea driver. -config USB_GADGET_MAX3420 - bool "MAX3420 USB Over SPI" - depends on DM_SPI - help - MAX3420, from MAXIM, implements USB-over-SPI Full-Speed device controller. - config USB_GADGET_VBUS_DRAW int "Maximum VBUS Power usage (2-500 mA)" range 2 500 diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index db5f8895a33..f2aebf4e480 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -17,10 +17,8 @@ endif ifdef CONFIG_USB_GADGET obj-$(CONFIG_USB_GADGET_AT91) += at91_udc.o obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o -obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o -obj-$(CONFIG_USB_GADGET_MAX3420) += max3420_udc.o obj-$(CONFIG_USB_RENESAS_USBHS) += rcar/ ifndef CONFIG_XPL_BUILD obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 72f68dba3a7..f7a92ded6da 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1147,7 +1147,7 @@ static int usba_udc_irq(struct usba_udc *udc) reset_all_endpoints(udc); if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver->disconnect) { + udc->driver && udc->driver->disconnect) { udc->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); diff --git a/drivers/usb/gadget/bcm_udc_otg.h b/drivers/usb/gadget/bcm_udc_otg.h deleted file mode 100644 index 48370f37d8a..00000000000 --- a/drivers/usb/gadget/bcm_udc_otg.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2015 Broadcom Corporation. - */ - -#ifndef __BCM_UDC_OTG_H -#define __BCM_UDC_OTG_H - -static inline void wfld_set(uintptr_t addr, uint32_t fld_val, uint32_t fld_mask) -{ - writel(((readl(addr) & ~(fld_mask)) | (fld_val)), (addr)); -} - -static inline void wfld_clear(uintptr_t addr, uint32_t fld_mask) -{ - writel((readl(addr) & ~(fld_mask)), (addr)); -} - -#endif diff --git a/drivers/usb/gadget/bcm_udc_otg_phy.c b/drivers/usb/gadget/bcm_udc_otg_phy.c deleted file mode 100644 index 9875191091c..00000000000 --- a/drivers/usb/gadget/bcm_udc_otg_phy.c +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2015 Broadcom Corporation. - */ - -#include <config.h> -#include <asm/io.h> -#include <asm/arch/sysmap.h> -#include <asm/kona-common/clk.h> -#include <linux/delay.h> - -#include "dwc2_udc_otg_priv.h" -#include "bcm_udc_otg.h" - -void otg_phy_init(struct dwc2_udc *dev) -{ - /* turn on the USB OTG clocks */ - clk_usb_otg_enable((void *)HSOTG_BASE_ADDR); - - /* set Phy to driving mode */ - wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK); - - udelay(100); - - /* clear Soft Disconnect */ - wfld_clear(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET, - HSOTG_DCTL_SFTDISCON_MASK); - - /* invoke Reset (active low) */ - wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK); - - /* Reset needs to be asserted for 2ms */ - udelay(2000); - - /* release Reset */ - wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK, - HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK); -} - -void otg_phy_off(struct dwc2_udc *dev) -{ - /* Soft Disconnect */ - wfld_set(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET, - HSOTG_DCTL_SFTDISCON_MASK, - HSOTG_DCTL_SFTDISCON_MASK); - - /* set Phy to non-driving (reset) mode */ - wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK, - HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK); -} diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index fca052b4556..5a7f50ebaa5 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -526,7 +526,7 @@ static int dwc2_udc_irq(int irq, void *_dev) if (gotgint & GOTGINT_SES_END_DET) { debug_cond(DEBUG_ISR, "\t\tSession End Detected\n"); /* Let gadget detect disconnected state */ - if (dev->driver->disconnect) { + if (dev->driver && dev->driver->disconnect) { spin_unlock_irqrestore(&dev->lock, flags); dev->driver->disconnect(&dev->gadget); spin_lock_irqsave(&dev->lock, flags); diff --git a/drivers/usb/gadget/max3420_udc.c b/drivers/usb/gadget/max3420_udc.c deleted file mode 100644 index 557a1f0644e..00000000000 --- a/drivers/usb/gadget/max3420_udc.c +++ /dev/null @@ -1,879 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ - -#include <linux/errno.h> -#include <linux/delay.h> -#include <asm/gpio.h> -#include <linux/list.h> -#include <linux/bitfield.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <malloc.h> -#include <spi.h> -#include <dm.h> -#include <g_dnl.h> - -#define MAX3420_MAX_EPS 4 -#define EP_MAX_PACKET 64 /* Same for all Endpoints */ -#define EPNAME_SIZE 16 /* Buffer size for endpoint name */ - -#define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */ -#define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */ - -/* SPI commands: */ -#define MAX3420_SPI_ACK_MASK BIT(0) -#define MAX3420_SPI_DIR_MASK BIT(1) -#define MAX3420_SPI_REG_MASK GENMASK(7, 3) - -#define MAX3420_REG_EP0FIFO 0 -#define MAX3420_REG_EP1FIFO 1 -#define MAX3420_REG_EP2FIFO 2 -#define MAX3420_REG_EP3FIFO 3 -#define MAX3420_REG_SUDFIFO 4 -#define MAX3420_REG_EP0BC 5 -#define MAX3420_REG_EP1BC 6 -#define MAX3420_REG_EP2BC 7 -#define MAX3420_REG_EP3BC 8 - -#define MAX3420_REG_EPSTALLS 9 - #define bACKSTAT BIT(6) - #define bSTLSTAT BIT(5) - #define bSTLEP3IN BIT(4) - #define bSTLEP2IN BIT(3) - #define bSTLEP1OUT BIT(2) - #define bSTLEP0OUT BIT(1) - #define bSTLEP0IN BIT(0) - -#define MAX3420_REG_CLRTOGS 10 - #define bEP3DISAB BIT(7) - #define bEP2DISAB BIT(6) - #define bEP1DISAB BIT(5) - #define bCTGEP3IN BIT(4) - #define bCTGEP2IN BIT(3) - #define bCTGEP1OUT BIT(2) - -#define MAX3420_REG_EPIRQ 11 -#define MAX3420_REG_EPIEN 12 - #define bSUDAVIRQ BIT(5) - #define bIN3BAVIRQ BIT(4) - #define bIN2BAVIRQ BIT(3) - #define bOUT1DAVIRQ BIT(2) - #define bOUT0DAVIRQ BIT(1) - #define bIN0BAVIRQ BIT(0) - -#define MAX3420_REG_USBIRQ 13 -#define MAX3420_REG_USBIEN 14 - #define bOSCOKIRQ BIT(0) - #define bRWUDNIRQ BIT(1) - #define bBUSACTIRQ BIT(2) - #define bURESIRQ BIT(3) - #define bSUSPIRQ BIT(4) - #define bNOVBUSIRQ BIT(5) - #define bVBUSIRQ BIT(6) - #define bURESDNIRQ BIT(7) - -#define MAX3420_REG_USBCTL 15 - #define bHOSCSTEN BIT(7) - #define bVBGATE BIT(6) - #define bCHIPRES BIT(5) - #define bPWRDOWN BIT(4) - #define bCONNECT BIT(3) - #define bSIGRWU BIT(2) - -#define MAX3420_REG_CPUCTL 16 - #define bIE BIT(0) - -#define MAX3420_REG_PINCTL 17 - #define bEP3INAK BIT(7) - #define bEP2INAK BIT(6) - #define bEP0INAK BIT(5) - #define bFDUPSPI BIT(4) - #define bINTLEVEL BIT(3) - #define bPOSINT BIT(2) - #define bGPXB BIT(1) - #define bGPXA BIT(0) - -#define MAX3420_REG_REVISION 18 - -#define MAX3420_REG_FNADDR 19 - #define FNADDR_MASK 0x7f - -#define MAX3420_REG_IOPINS 20 -#define MAX3420_REG_IOPINS2 21 -#define MAX3420_REG_GPINIRQ 22 -#define MAX3420_REG_GPINIEN 23 -#define MAX3420_REG_GPINPOL 24 -#define MAX3420_REG_HIRQ 25 -#define MAX3420_REG_HIEN 26 -#define MAX3420_REG_MODE 27 -#define MAX3420_REG_PERADDR 28 -#define MAX3420_REG_HCTL 29 -#define MAX3420_REG_HXFR 30 -#define MAX3420_REG_HRSL 31 - -struct max3420_req { - struct usb_request usb_req; - struct list_head queue; - struct max3420_ep *ep; -}; - -struct max3420_ep { - struct max3420_udc *udc; - struct list_head queue; - char name[EPNAME_SIZE]; - unsigned int maxpacket; - struct usb_ep ep_usb; - int halted; - int id; -}; - -struct max3420_udc { - struct max3420_ep ep[MAX3420_MAX_EPS]; - struct usb_gadget_driver *driver; - bool softconnect; - struct usb_ctrlrequest setup; - struct max3420_req ep0req; - struct usb_gadget gadget; - struct spi_slave *slave; - struct udevice *dev; - u8 ep0buf[64]; - int remote_wkp; - bool suspended; -}; - -#define to_max3420_req(r) container_of((r), struct max3420_req, usb_req) -#define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb) -#define to_udc(g) container_of((g), struct max3420_udc, gadget) - -static void spi_ack_ctrl(struct max3420_udc *udc) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[1]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_ACK_MASK, 1); - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE); -} - -static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int ackstat) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[2], rxdata[2]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD) | - FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0); - - rxdata[0] = 0; - rxdata[1] = 0; - spi_xfer(slave, sizeof(txdata), txdata, rxdata, SPI_XFER_ONCE); - - return rxdata[1]; -} - -static u8 spi_rd8(struct max3420_udc *udc, u8 reg) -{ - return spi_rd8_ack(udc, reg, 0); -} - -static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int ackstat) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[2]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR) | - FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0); - txdata[1] = val; - - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE); -} - -static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val) -{ - spi_wr8_ack(udc, reg, val, 0); -} - -static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[1]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD); - - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN); - spi_xfer(slave, len * 8, NULL, buf, SPI_XFER_END); -} - -static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[1]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR); - - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN); - spi_xfer(slave, len * 8, buf, NULL, SPI_XFER_END); -} - -/* 0 if not-connected */ -int g_dnl_board_usb_cable_connected(void) -{ - return 1; -} - -static void spi_max3420_enable(struct max3420_ep *ep, int enable) -{ - struct max3420_udc *udc = ep->udc; - u8 epdis, epien; - - if (ep->id == 0) - return; - - epien = spi_rd8(udc, MAX3420_REG_EPIEN); - epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS); - - if (enable) { - epdis &= ~BIT(ep->id + 4); - epien |= BIT(ep->id + 1); - } else { - epdis |= BIT(ep->id + 4); - epien &= ~BIT(ep->id + 1); - } - - spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis); - spi_wr8(udc, MAX3420_REG_EPIEN, epien); -} - -static int -max3420_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - - _ep->desc = desc; - _ep->maxpacket = usb_endpoint_maxp(desc) & 0x7ff; - - spi_max3420_enable(ep, 1); - - return 0; -} - -static void max3420_req_done(struct max3420_req *req, int status) -{ - struct max3420_ep *ep = req->ep; - - if (req->usb_req.status == -EINPROGRESS) - req->usb_req.status = status; - else - status = req->usb_req.status; - - if (status && status != -ESHUTDOWN) - dev_err(ep->udc->dev, "%s done %p, status %d\n", - ep->ep_usb.name, req, status); - - if (req->usb_req.complete) - req->usb_req.complete(&ep->ep_usb, &req->usb_req); -} - -static void max3420_ep_nuke(struct max3420_ep *ep, int status) -{ - struct max3420_req *req, *r; - - list_for_each_entry_safe(req, r, &ep->queue, queue) { - list_del_init(&req->queue); - max3420_req_done(req, status); - } -} - -static int max3420_ep_disable(struct usb_ep *_ep) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - - _ep->desc = NULL; - max3420_ep_nuke(ep, -ESHUTDOWN); - spi_max3420_enable(ep, 0); - - return 0; -} - -static struct usb_request * -max3420_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - struct max3420_req *req = kzalloc(sizeof(*req), gfp_flags); - - if (!req) - return NULL; - - req->ep = ep; - INIT_LIST_HEAD(&req->queue); - - return &req->usb_req; -} - -static void -max3420_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - kfree(to_max3420_req(_req)); -} - -static int -max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct max3420_req *req = to_max3420_req(_req); - struct max3420_ep *ep = to_max3420_ep(_ep); - - _req->status = -EINPROGRESS; - _req->actual = 0; - list_add_tail(&req->queue, &ep->queue); - - return 0; -} - -static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct max3420_req *req = to_max3420_req(_req); - - list_del_init(&req->queue); - max3420_req_done(req, -ECONNRESET); - - return 0; -} - -static int max3420_ep_set_halt(struct usb_ep *_ep, int halt) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - struct max3420_udc *udc = ep->udc; - u8 epstalls; - - if (ep->id == 0) /* can't stall EP0 */ - return 0; - - epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS); - if (halt) { - ep->halted = 1; - epstalls |= BIT(ep->id + 1); - } else { - u8 clrtogs; - - ep->halted = 0; - epstalls &= ~BIT(ep->id + 1); - clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS); - clrtogs |= BIT(ep->id + 1); - spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs); - } - spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | bACKSTAT); - - return 0; -} - -static const struct usb_ep_ops max3420_ep_ops = { - .enable = max3420_ep_enable, - .disable = max3420_ep_disable, - .alloc_request = max3420_ep_alloc_request, - .free_request = max3420_ep_free_request, - .queue = max3420_ep_queue, - .dequeue = max3420_ep_dequeue, - .set_halt = max3420_ep_set_halt, -}; - -static void __max3420_stop(struct max3420_udc *udc) -{ - u8 val; - - /* Disable IRQ to CPU */ - spi_wr8(udc, MAX3420_REG_CPUCTL, 0); - - val = spi_rd8(udc, MAX3420_REG_USBCTL); - val |= bPWRDOWN; - val |= bHOSCSTEN; - spi_wr8(udc, MAX3420_REG_USBCTL, val); -} - -static void __max3420_start(struct max3420_udc *udc) -{ - u8 val; - - /* configure SPI */ - spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI); - - /* Chip Reset */ - spi_wr8(udc, MAX3420_REG_USBCTL, bCHIPRES); - mdelay(5); - spi_wr8(udc, MAX3420_REG_USBCTL, 0); - - /* Poll for OSC to stabilize */ - while (1) { - val = spi_rd8(udc, MAX3420_REG_USBIRQ); - if (val & bOSCOKIRQ) - break; - cond_resched(); - } - - /* Enable PULL-UP only when Vbus detected */ - val = spi_rd8(udc, MAX3420_REG_USBCTL); - val |= bVBGATE | bCONNECT; - spi_wr8(udc, MAX3420_REG_USBCTL, val); - - val = bURESDNIRQ | bURESIRQ; - spi_wr8(udc, MAX3420_REG_USBIEN, val); - - /* Enable only EP0 interrupts */ - val = bIN0BAVIRQ | bOUT0DAVIRQ | bSUDAVIRQ; - spi_wr8(udc, MAX3420_REG_EPIEN, val); - - /* Enable IRQ to CPU */ - spi_wr8(udc, MAX3420_REG_CPUCTL, bIE); -} - -static int max3420_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct max3420_udc *udc = to_udc(gadget); - - udc->driver = driver; - udc->remote_wkp = 0; - udc->softconnect = true; - - __max3420_start(udc); - - return 0; -} - -static int max3420_udc_stop(struct usb_gadget *gadget) -{ - struct max3420_udc *udc = to_udc(gadget); - - udc->driver = NULL; - udc->softconnect = false; - - __max3420_stop(udc); - - return 0; -} - -static int max3420_wakeup(struct usb_gadget *gadget) -{ - struct max3420_udc *udc = to_udc(gadget); - u8 usbctl; - - /* Only if wakeup allowed by host */ - if (!udc->remote_wkp || !udc->suspended) - return 0; - - /* Set Remote-Wakeup Signal*/ - usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); - usbctl |= bSIGRWU; - spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); - - mdelay(5); - - /* Clear Remote-WkUp Signal*/ - usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); - usbctl &= ~bSIGRWU; - spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); - - udc->suspended = false; - - return 0; -} - -static const struct usb_gadget_ops max3420_udc_ops = { - .udc_start = max3420_udc_start, - .udc_stop = max3420_udc_stop, - .wakeup = max3420_wakeup, -}; - -static struct usb_endpoint_descriptor ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(EP_MAX_PACKET), -}; - -static void max3420_getstatus(struct max3420_udc *udc) -{ - struct max3420_ep *ep; - u16 status = 0; - - switch (udc->setup.bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - /* Get device status */ - status = 0 << USB_DEVICE_SELF_POWERED; - status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP); - break; - case USB_RECIP_INTERFACE: - if (udc->driver->setup(&udc->gadget, &udc->setup) < 0) - goto stall; - break; - case USB_RECIP_ENDPOINT: - ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK]; - if (ep->halted) - status = 1 << USB_ENDPOINT_HALT; - break; - default: - goto stall; - } - - status = cpu_to_le16(status); - spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2); - spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1); - return; -stall: - dev_err(udc->dev, "Can't respond to getstatus request\n"); - spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); -} - -static void max3420_set_clear_feature(struct max3420_udc *udc) -{ - int set = udc->setup.bRequest == USB_REQ_SET_FEATURE; - struct max3420_ep *ep; - int id; - - switch (udc->setup.bRequestType) { - case USB_RECIP_DEVICE: - if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP) - break; - - if (udc->setup.bRequest == USB_REQ_SET_FEATURE) - udc->remote_wkp = 1; - else - udc->remote_wkp = 0; - - return spi_ack_ctrl(udc); - - case USB_RECIP_ENDPOINT: - if (udc->setup.wValue != USB_ENDPOINT_HALT) - break; - - id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK; - ep = &udc->ep[id]; - - max3420_ep_set_halt(&ep->ep_usb, set); - return; - default: - break; - } - - dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n"); - spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); -} - -static void max3420_handle_setup(struct max3420_udc *udc) -{ - struct usb_ctrlrequest setup; - u8 addr; - - spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8); - - udc->setup = setup; - udc->setup.wValue = cpu_to_le16(setup.wValue); - udc->setup.wIndex = cpu_to_le16(setup.wIndex); - udc->setup.wLength = cpu_to_le16(setup.wLength); - - switch (udc->setup.bRequest) { - case USB_REQ_GET_STATUS: - /* Data+Status phase form udc */ - if ((udc->setup.bRequestType & - (USB_DIR_IN | USB_TYPE_MASK)) != - (USB_DIR_IN | USB_TYPE_STANDARD)) { - break; - } - return max3420_getstatus(udc); - case USB_REQ_SET_ADDRESS: - /* Status phase from udc */ - if (udc->setup.bRequestType != (USB_DIR_OUT | - USB_TYPE_STANDARD | USB_RECIP_DEVICE)) - break; - addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1); - dev_dbg(udc->dev, "Assigned Address=%d/%d\n", - udc->setup.wValue, addr); - return; - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - /* Requests with no data phase, status phase from udc */ - if ((udc->setup.bRequestType & USB_TYPE_MASK) - != USB_TYPE_STANDARD) - break; - return max3420_set_clear_feature(udc); - default: - break; - } - - if (udc->driver->setup(&udc->gadget, &setup) < 0) { - /* Stall EP0 */ - spi_wr8(udc, MAX3420_REG_EPSTALLS, - bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); - } -} - -static int do_data(struct max3420_udc *udc, int ep_id, int in) -{ - struct max3420_ep *ep = &udc->ep[ep_id]; - struct max3420_req *req; - int done, length, psz; - void *buf; - - if (list_empty(&ep->queue)) - return 0; - - req = list_first_entry(&ep->queue, struct max3420_req, queue); - buf = req->usb_req.buf + req->usb_req.actual; - - psz = ep->ep_usb.maxpacket; - length = req->usb_req.length - req->usb_req.actual; - length = min(length, psz); - - if (length == 0) { - done = 1; - goto xfer_done; - } - - done = 0; - if (in) { - spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); - spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length); - if (length < psz) - done = 1; - } else { - psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id); - length = min(length, psz); - spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); - if (length < ep->ep_usb.maxpacket) - done = 1; - } - - req->usb_req.actual += length; - - if (req->usb_req.actual == req->usb_req.length) - done = 1; - -xfer_done: - if (done) { - list_del_init(&req->queue); - - if (ep_id == 0) - spi_ack_ctrl(udc); - - max3420_req_done(req, 0); - } - - return 1; -} - -static int max3420_handle_irqs(struct max3420_udc *udc) -{ - u8 epien, epirq, usbirq, usbien, reg[4]; - int ret = 0; - - spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4); - epirq = reg[0]; - epien = reg[1]; - usbirq = reg[2]; - usbien = reg[3]; - - usbirq &= usbien; - epirq &= epien; - - if (epirq & bSUDAVIRQ) { - spi_wr8(udc, MAX3420_REG_EPIRQ, bSUDAVIRQ); - max3420_handle_setup(udc); - return 1; - } - - if (usbirq & bVBUSIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bVBUSIRQ); - dev_dbg(udc->dev, "Cable plugged in\n"); - g_dnl_clear_detach(); - return 1; - } - - if (usbirq & bNOVBUSIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bNOVBUSIRQ); - dev_dbg(udc->dev, "Cable pulled out\n"); - g_dnl_trigger_detach(); - return 1; - } - - if (usbirq & bURESIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bURESIRQ); - return 1; - } - - if (usbirq & bURESDNIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bURESDNIRQ); - spi_wr8(udc, MAX3420_REG_USBIEN, bURESDNIRQ | bURESIRQ); - spi_wr8(udc, MAX3420_REG_EPIEN, bSUDAVIRQ - | bIN0BAVIRQ | bOUT0DAVIRQ); - return 1; - } - - if (usbirq & bSUSPIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bSUSPIRQ); - dev_dbg(udc->dev, "USB Suspend - Enter\n"); - udc->suspended = true; - return 1; - } - - if (usbirq & bBUSACTIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bBUSACTIRQ); - dev_dbg(udc->dev, "USB Suspend - Exit\n"); - udc->suspended = false; - return 1; - } - - if (usbirq & bRWUDNIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bRWUDNIRQ); - dev_dbg(udc->dev, "Asked Host to wakeup\n"); - return 1; - } - - if (usbirq & bOSCOKIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bOSCOKIRQ); - dev_dbg(udc->dev, "Osc stabilized, start work\n"); - return 1; - } - - if (epirq & bOUT0DAVIRQ && do_data(udc, 0, 0)) { - spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT0DAVIRQ, 1); - ret = 1; - } - - if (epirq & bIN0BAVIRQ && do_data(udc, 0, 1)) - ret = 1; - - if (epirq & bOUT1DAVIRQ && do_data(udc, 1, 0)) { - spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT1DAVIRQ, 1); - ret = 1; - } - - if (epirq & bIN2BAVIRQ && do_data(udc, 2, 1)) - ret = 1; - - if (epirq & bIN3BAVIRQ && do_data(udc, 3, 1)) - ret = 1; - - return ret; -} - -static int max3420_irq(struct max3420_udc *udc) -{ - do_data(udc, 0, 1); /* get done with the EP0 ZLP */ - - return max3420_handle_irqs(udc); -} - -static void max3420_setup_eps(struct max3420_udc *udc) -{ - int i; - - INIT_LIST_HEAD(&udc->gadget.ep_list); - INIT_LIST_HEAD(&udc->ep[0].ep_usb.ep_list); - - for (i = 0; i < MAX3420_MAX_EPS; i++) { - struct max3420_ep *ep = &udc->ep[i]; - - INIT_LIST_HEAD(&ep->queue); - - ep->id = i; - ep->udc = udc; - ep->ep_usb.ops = &max3420_ep_ops; - ep->ep_usb.name = ep->name; - ep->ep_usb.maxpacket = EP_MAX_PACKET; - - if (i == 0) { - ep->ep_usb.desc = &ep0_desc; - snprintf(ep->name, EPNAME_SIZE, "ep0"); - continue; - } - - list_add_tail(&ep->ep_usb.ep_list, &udc->gadget.ep_list); - - if (i == 1) - snprintf(ep->name, EPNAME_SIZE, "ep1out-bulk"); - else - snprintf(ep->name, EPNAME_SIZE, "ep%din-bulk", i); - }; -} - -static void max3420_setup_spi(struct max3420_udc *udc) -{ - u8 reg[8]; - - spi_claim_bus(udc->slave); - spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8); - /* configure SPI */ - spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI); -} - -static int max3420_udc_probe(struct udevice *dev) -{ - struct max3420_udc *udc = dev_get_priv(dev); - struct dm_spi_slave_plat *slave_pdata; - struct udevice *bus = dev->parent; - int busnum = dev_seq(bus); - unsigned int cs; - uint speed, mode; - struct udevice *spid; - - slave_pdata = dev_get_parent_plat(dev); - cs = slave_pdata->cs; - speed = slave_pdata->max_hz; - mode = slave_pdata->mode; - _spi_get_bus_and_cs(busnum, cs, speed, mode, false, "spi_generic_drv", - NULL, &spid, &udc->slave); - - udc->dev = dev; - udc->gadget.ep0 = &udc->ep[0].ep_usb; - udc->gadget.max_speed = USB_SPEED_FULL; - udc->gadget.speed = USB_SPEED_FULL; - udc->gadget.is_dualspeed = 0; - udc->gadget.ops = &max3420_udc_ops; - udc->gadget.name = "max3420-udc"; - - max3420_setup_eps(udc); - max3420_setup_spi(udc); - - usb_add_gadget_udc((struct device *)dev, &udc->gadget); - - return 0; -} - -static int max3420_udc_remove(struct udevice *dev) -{ - struct max3420_udc *udc = dev_get_priv(dev); - - usb_del_gadget_udc(&udc->gadget); - - spi_release_bus(udc->slave); - - return 0; -} - -static int max3420_gadget_handle_interrupts(struct udevice *dev) -{ - struct max3420_udc *udc = dev_get_priv(dev); - - return max3420_irq(udc); -} - -static const struct usb_gadget_generic_ops max3420_gadget_ops = { - .handle_interrupts = max3420_gadget_handle_interrupts, -}; - -static const struct udevice_id max3420_ids[] = { - { .compatible = "maxim,max3421-udc" }, - { } -}; - -U_BOOT_DRIVER(max3420_generic_udc) = { - .name = "max3420-udc", - .id = UCLASS_USB_GADGET_GENERIC, - .of_match = max3420_ids, - .ops = &max3420_gadget_ops, - .probe = max3420_udc_probe, - .remove = max3420_udc_remove, - .priv_auto = sizeof(struct max3420_udc), -}; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 5c9e8fc9d15..2cf687fc4f3 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -121,8 +121,9 @@ config USB_XHCI_DRA7XX_INDEX config USB_XHCI_FSL bool "Support for NXP Layerscape on-chip xHCI USB controller" - default y if ARCH_LS1021A || FSL_LSCH3 || FSL_LSCH2 + depends on ARCH_LS1021A || FSL_LSCH3 || FSL_LSCH2 depends on !SPL_NO_USB + default y help Enables support for the on-chip xHCI controller on NXP Layerscape SoCs. @@ -286,7 +287,8 @@ config USB_EHCI_TEGRA config USB_EHCI_ZYNQ bool "Support for Xilinx Zynq on-chip EHCI USB controller" - default y if ARCH_ZYNQ + depends on ARCH_ZYNQ + default y select USB_EHCI_IS_TDI ---help--- Enable support for Zynq on-chip EHCI USB controller @@ -303,6 +305,7 @@ config EHCI_HCD_INIT_AFTER_RESET config USB_EHCI_FSL bool "Support for FSL on-chip EHCI USB controller" + depends on PPC select EHCI_HCD_INIT_AFTER_RESET select SYS_FSL_USB_INTERNAL_UTMI_PHY if MPC85xx && \ !(ARCH_B4860 || ARCH_B4420 || ARCH_P4080 || ARCH_P1020 || ARCH_P2020) @@ -362,6 +365,7 @@ config USB_OHCI_GENERIC config USB_OHCI_DA8XX bool "Support for da850 OHCI USB controller" + depends on ARCH_DAVINCI help Enable support for the da850 USB controller. diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig index ad9072a5327..0e2b2b5fb85 100644 --- a/drivers/usb/musb-new/Kconfig +++ b/drivers/usb/musb-new/Kconfig @@ -52,9 +52,11 @@ config USB_MUSB_OMAP2PLUS config USB_MUSB_AM35X bool "AM35x" + depends on ARCH_OMAP2PLUS config USB_MUSB_DSPS bool "TI DSPS platforms" + depends on ARCH_OMAP2PLUS config USB_MUSB_MT85XX bool "Enable Mediatek MT85XX DRC USB controller" diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c index 2f999fc8bbe..4224e3c17f4 100644 --- a/drivers/virtio/virtio_blk.c +++ b/drivers/virtio/virtio_blk.c @@ -12,10 +12,17 @@ #include <virtio_types.h> #include <virtio.h> #include <virtio_ring.h> +#include <linux/log2.h> #include "virtio_blk.h" +/** + * struct virtio_blk_priv - private date for virtio block device + */ struct virtio_blk_priv { + /** @virtqueue - virtqueue to process */ struct virtqueue *vq; + /** @blksz_shift - log2 of block size divided by 512 */ + u32 blksz_shift; }; static const u32 feature[] = { @@ -71,6 +78,8 @@ static ulong virtio_blk_do_req(struct udevice *dev, u64 sector, u8 status; int ret; + sector <<= priv->blksz_shift; + blkcnt <<= priv->blksz_shift; virtio_blk_init_header_sg(dev, sector, type, &out_hdr, &hdr_sg); sgs[num_out++] = &hdr_sg; @@ -109,7 +118,7 @@ static ulong virtio_blk_do_req(struct udevice *dev, u64 sector, ; log_debug("done\n"); - return status == VIRTIO_BLK_S_OK ? blkcnt : -EIO; + return status == VIRTIO_BLK_S_OK ? blkcnt >> priv->blksz_shift : -EIO; } static ulong virtio_blk_read(struct udevice *dev, lbaint_t start, @@ -177,15 +186,25 @@ static int virtio_blk_probe(struct udevice *dev) struct blk_desc *desc = dev_get_uclass_plat(dev); u64 cap; int ret; + u32 blk_size; ret = virtio_find_vqs(dev, 1, &priv->vq); if (ret) return ret; - desc->blksz = 512; - desc->log2blksz = 9; virtio_cread(dev, struct virtio_blk_config, capacity, &cap); desc->lba = cap; + if (!virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) { + virtio_cread(dev, struct virtio_blk_config, blk_size, &blk_size); + desc->blksz = blk_size; + if (!is_power_of_2(blk_size) || desc->blksz < 512) + return -EIO; + } else { + desc->blksz = 512; + } + desc->log2blksz = LOG2(desc->blksz); + priv->blksz_shift = desc->log2blksz - 9; + desc->lba >>= priv->blksz_shift; return 0; } diff --git a/drivers/w1-eeprom/ds24xxx.c b/drivers/w1-eeprom/ds24xxx.c index 413d8bc5881..801fade6f49 100644 --- a/drivers/w1-eeprom/ds24xxx.c +++ b/drivers/w1-eeprom/ds24xxx.c @@ -53,7 +53,7 @@ U_BOOT_DRIVER(ds24xxx) = { .probe = ds24xxx_probe, }; -u8 family_supported[] = { +static u8 family_supported[] = { W1_FAMILY_DS24B33, W1_FAMILY_DS2431, }; diff --git a/drivers/w1-eeprom/ds2502.c b/drivers/w1-eeprom/ds2502.c index db9f41e9726..981b41a34b2 100644 --- a/drivers/w1-eeprom/ds2502.c +++ b/drivers/w1-eeprom/ds2502.c @@ -243,7 +243,7 @@ U_BOOT_DRIVER(ds2502) = { .probe = ds2502_probe, }; -u8 family_supported[] = { +static u8 family_supported[] = { W1_FAMILY_DS2502, }; |