diff options
| author | Tom Rini <[email protected]> | 2026-05-25 11:35:35 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-05-25 11:35:35 -0600 |
| commit | 7bb1917b15b77a7d8c27045df33b6bbc214c2f67 (patch) | |
| tree | a69ef73f30019b611aa7c4d79012447bb8030dbb /drivers | |
| parent | bb354d04459f5425318aeb8a70bae995ee573f1d (diff) | |
| parent | 76d62273bc8a5dc126ed79ed0fb65e5a97359577 (diff) | |
Merge tag 'v2026.07-rc3' into next
Prepare v2026.07-rc3
Diffstat (limited to 'drivers')
29 files changed, 914 insertions, 476 deletions
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 99b6c7534fd..4c0c8d89bb4 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -6,7 +6,7 @@ menuconfig BOOTCOUNT_LIMIT bool "Enable support for checking boot count limit" help Enable checking for exceeding the boot count limit. - More information: https://docs.u-boot.org/en/latest/api/bootcount.html + More information: https://docs.u-boot-project.org/en/latest/api/bootcount.html if BOOTCOUNT_LIMIT diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 51c87cc3606..72f99e9fa1b 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -157,6 +157,12 @@ config CLK_R8A779H0 help Enable this to support the clocks on Renesas R8A779H0 SoC. +config CLK_R8A78000 + bool "Renesas R8A78000 clock driver" + depends on CLK_RENESAS + help + Enable this to support the clocks on Renesas R8A78000 SoC. + config CLK_R9A06G032 bool "Renesas R9A06G032 clock driver" depends on CLK_RENESAS diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 354035baf2d..fb8d4c1f2f6 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_CLK_R8A779A0) += r8a779a0-cpg-mssr.o obj-$(CONFIG_CLK_R8A779F0) += r8a779f0-cpg-mssr.o obj-$(CONFIG_CLK_R8A779G0) += r8a779g0-cpg-mssr.o obj-$(CONFIG_CLK_R8A779H0) += r8a779h0-cpg-mssr.o +obj-$(CONFIG_CLK_R8A78000) += r8a78000-cpg.o obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_RZG2L) += rzg2l-cpg.o obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o diff --git a/drivers/clk/renesas/r8a78000-cpg.c b/drivers/clk/renesas/r8a78000-cpg.c new file mode 100644 index 00000000000..e9ca06476f6 --- /dev/null +++ b/drivers/clk/renesas/r8a78000-cpg.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Renesas R-Car Gen5 CPG driver + * + * Copyright (C) 2026 Marek Vasut <[email protected]> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/clk-provider.h> + +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> + +#include <dt-bindings/clock/r8a78000-clock-scmi.h> + +#if IS_ENABLED(CONFIG_CLK_SCMI) +struct gen5_clk_priv { + struct udevice *clk; + u32 basever; +}; + +static struct clk *gen5_clk_get_by_scmi_id(struct clk *clk) +{ + struct gen5_clk_priv *priv = dev_get_priv(clk->dev); + struct udevice *sdev; + struct uclass *uc; + + uclass_id_foreach_dev(UCLASS_CLK, sdev, uc) + if (sdev->seq_ == priv->clk->seq_ + clk->id + 1) + return dev_get_clk_ptr(sdev); + + return NULL; +} + +static ulong gen5_clk_round_rate(struct clk *clk, ulong rate) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_round_rate(scmi, rate); +} + +static ulong gen5_clk_get_rate(struct clk *clk) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_get_rate(scmi); +} + +static ulong gen5_clk_set_rate(struct clk *clk, ulong rate) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_set_rate(scmi, rate); +} + +static int gen5_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_set_parent(scmi, parent); +} + +static int gen5_clk_enable(struct clk *clk) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_enable(scmi); +} + +static int gen5_clk_disable(struct clk *clk) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_disable(scmi); +} + +struct clk_map_in { + u16 dt_id; /* DT binding clock ID */ + u16 fw_id; /* SCMI firmware clock ID */ +}; + +#define GEN5_SCMI_SDK_4_28 0x010a0000 +#define GEN5_SCMI_SDK_4_29 0x010b0000 +#define GEN5_SCMI_SDK_4_30 0x010c0000 +#define GEN5_SCMI_SDK_4_31 0x010d0000 +#define GEN5_SCMI_SDK_4_32 0x010e0000 + +static const struct clk_map_in gen5_clk_map_dt_sdk_4_28[] = { + { SCP_CLOCK_ID_MDLC_UFS0, 202 }, + { SCP_CLOCK_ID_MDLC_UFS1, 203 }, + { SCP_CLOCK_ID_MDLC_SDHI0, 204 }, + { SCP_CLOCK_ID_MDLC_XPCS0, 316 }, + { SCP_CLOCK_ID_MDLC_XPCS1, 317 }, + { SCP_CLOCK_ID_MDLC_XPCS2, 318 }, + { SCP_CLOCK_ID_MDLC_XPCS3, 319 }, + { SCP_CLOCK_ID_MDLC_XPCS4, 320 }, + { SCP_CLOCK_ID_MDLC_XPCS5, 321 }, + { SCP_CLOCK_ID_MDLC_XPCS6, 322 }, + { SCP_CLOCK_ID_MDLC_XPCS7, 323 }, + { SCP_CLOCK_ID_MDLC_RSW3, 324 }, + { SCP_CLOCK_ID_MDLC_RSW3TSN, 325 }, + { SCP_CLOCK_ID_MDLC_RSW3AES, 326 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES0, 327 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES1, 328 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES2, 329 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES3, 330 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES4, 331 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES5, 332 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES6, 333 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES7, 334 }, + { SCP_CLOCK_ID_MDLC_RSW3MFWD, 335 }, + { SCP_CLOCK_ID_MDLC_MPPHY01, 344 }, + { SCP_CLOCK_ID_MDLC_MPPHY11, 345 }, + { SCP_CLOCK_ID_MDLC_MPPHY21, 346 }, + { SCP_CLOCK_ID_MDLC_MPPHY31, 347 }, + { SCP_CLOCK_ID_MDLC_MPPHY02, 348 }, + { SCP_CLOCK_ID_CLK_S0D6_PERE_MAIN, 1691 }, +}; + +static const struct clk_map_in gen5_clk_map_dt_sdk_4_31[] = { + { SCP_CLOCK_ID_MDLC_UFS0, 198 }, + { SCP_CLOCK_ID_MDLC_UFS1, 199 }, + { SCP_CLOCK_ID_MDLC_SDHI0, 200 }, + { SCP_CLOCK_ID_MDLC_XPCS0, 312 }, + { SCP_CLOCK_ID_MDLC_XPCS1, 313 }, + { SCP_CLOCK_ID_MDLC_XPCS2, 314 }, + { SCP_CLOCK_ID_MDLC_XPCS3, 315 }, + { SCP_CLOCK_ID_MDLC_XPCS4, 316 }, + { SCP_CLOCK_ID_MDLC_XPCS5, 317 }, + { SCP_CLOCK_ID_MDLC_XPCS6, 318 }, + { SCP_CLOCK_ID_MDLC_XPCS7, 319 }, + { SCP_CLOCK_ID_MDLC_RSW3, 320 }, + { SCP_CLOCK_ID_MDLC_RSW3TSN, 321 }, + { SCP_CLOCK_ID_MDLC_RSW3AES, 322 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES0, 323 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES1, 324 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES2, 325 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES3, 326 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES4, 327 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES5, 328 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES6, 329 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES7, 330 }, + { SCP_CLOCK_ID_MDLC_RSW3MFWD, 331 }, + { SCP_CLOCK_ID_MDLC_MPPHY01, 340 }, + { SCP_CLOCK_ID_MDLC_MPPHY11, 341 }, + { SCP_CLOCK_ID_MDLC_MPPHY21, 342 }, + { SCP_CLOCK_ID_MDLC_MPPHY31, 343 }, + { SCP_CLOCK_ID_MDLC_MPPHY02, 344 }, + { SCP_CLOCK_ID_CLK_S0D6_PERE_MAIN, 1687 }, +}; + +static int gen5_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + struct gen5_clk_priv *priv = dev_get_priv(clk->dev); + const struct clk_map_in *map; + unsigned int map_size; + int i; + + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (priv->basever == GEN5_SCMI_SDK_4_28) { + map = gen5_clk_map_dt_sdk_4_28; + map_size = ARRAY_SIZE(gen5_clk_map_dt_sdk_4_28); + } else if (priv->basever == GEN5_SCMI_SDK_4_31 || + priv->basever == GEN5_SCMI_SDK_4_32) { + map = gen5_clk_map_dt_sdk_4_31; + map_size = ARRAY_SIZE(gen5_clk_map_dt_sdk_4_31); + } else { + printf("Unsupported SCMI base protocol version %x\n", priv->basever); + return -EINVAL; + } + + clk->id = -1; + for (i = 0; i < map_size; i++) { + if (map[i].dt_id != args->args[0]) + continue; + clk->id = map[i].fw_id; + break; + } + + if (clk->id == -1) + return -EINVAL; + + return 0; +} + +static const struct clk_ops gen5_clk_ops = { + .round_rate = gen5_clk_round_rate, + .get_rate = gen5_clk_get_rate, + .set_rate = gen5_clk_set_rate, + .set_parent = gen5_clk_set_parent, + .enable = gen5_clk_enable, + .disable = gen5_clk_disable, + .of_xlate = gen5_clk_of_xlate, +}; + +static int gen5_clk_probe(struct udevice *dev) +{ + struct gen5_clk_priv *priv = dev_get_priv(dev); + struct udevice *agent; + int ret; + + ret = uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent); + if (ret) + return ret; + + if (!agent) + return -ENODEV; + + priv->basever = scmi_impl_version(agent); + + return uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(scmi_clock), + &priv->clk); +} +#else +static int gen5_clk_enable(struct clk *clk) +{ + return 0; +} + +static int gen5_clk_disable(struct clk *clk) +{ + return 0; +} + +static int gen5_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + clk->id = args->args[0]; + + return 0; +} + +static const struct clk_ops gen5_clk_ops = { + .enable = gen5_clk_enable, + .disable = gen5_clk_disable, + .of_xlate = gen5_clk_of_xlate, +}; +#endif + +static const struct udevice_id r8a78000_mdlc_ids[] = { + { .compatible = "renesas,r8a78000-cpg", }, + { } +}; + +U_BOOT_DRIVER(clk_gen5) = { + .name = "clk_gen5", + .id = UCLASS_CLK, + .of_match = r8a78000_mdlc_ids, + .priv_auto = CONFIG_IS_ENABLED(CLK_SCMI, (sizeof(struct gen5_clk_priv)), (0)), + .ops = &gen5_clk_ops, + .probe = CONFIG_IS_ENABLED(CLK_SCMI, (gen5_clk_probe), (NULL)), + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 010bf99fbc6..832bfb55711 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -1341,7 +1341,7 @@ static const struct udevice_id sandbox_scmi_test_ids[] = { { } }; -struct scmi_agent_ops sandbox_scmi_test_ops = { +static const struct scmi_agent_ops sandbox_scmi_test_ops = { .of_get_channel = sandbox_scmi_of_get_channel, .process_msg = sandbox_scmi_test_process_msg, }; diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c index 630d1ecfea3..3cb56cc0dc9 100644 --- a/drivers/fpga/versalpl.c +++ b/drivers/fpga/versalpl.c @@ -17,7 +17,7 @@ static ulong versal_align_dma_buffer(ulong *buf, u32 len) if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) { new_buf = (ulong *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN); - memcpy(new_buf, buf, len); + memmove(new_buf, buf, len); buf = new_buf; } diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 55465dc1d46..37288a47eb7 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -624,26 +624,6 @@ config SH_I2C_CLOCK default 104000000 endif -config SYS_I2C_SOFT - bool "Legacy software I2C interface" - depends on !COMPILE_TEST - help - Enable the legacy software defined I2C interface - -config SYS_I2C_SOFT_SPEED - int "Software I2C bus speed" - depends on SYS_I2C_SOFT - default 100000 - help - Speed of the software I2C bus - -config SYS_I2C_SOFT_SLAVE - hex "Software I2C slave address" - depends on SYS_I2C_SOFT - default 0xfe - help - Slave address of the software I2C bus - config SYS_I2C_OCTEON bool "Octeon II/III/TX/TX2 I2C driver" depends on (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) && DM_I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 5fe30d0df4f..2da649e97d3 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -47,7 +47,6 @@ obj-$(CONFIG_SYS_I2C_RZ_RIIC) += rz_riic.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o -obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o obj-$(CONFIG_SYS_I2C_SUN6I_P2WI) += sun6i_p2wi.o obj-$(CONFIG_SYS_I2C_SUN8I_RSB) += sun8i_rsb.o diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index c21c412231c..ad4122c2abd 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/drivers/i2c/designware_i2c_pci.c @@ -168,7 +168,7 @@ static int dw_i2c_acpi_fill_ssdt(const struct udevice *dev, return 0; } -struct acpi_ops dw_i2c_acpi_ops = { +static struct acpi_ops dw_i2c_acpi_ops = { .fill_ssdt = dw_i2c_acpi_fill_ssdt, }; diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index 4102375e5b7..e69de29bb2d 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -1,418 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2009 - * Heiko Schocher, DENX Software Engineering, [email protected]. - * Changes for multibus/multiadapter I2C support. - * - * (C) Copyright 2001, 2002 - * Wolfgang Denk, DENX Software Engineering, [email protected]. - * - * This has been changed substantially by Gerald Van Baren, Custom IDEAS, - * [email protected]. It was heavily influenced by LiMon, written by - * Neil Russell. - * - * NOTE: This driver should be converted to driver model before June 2017. - * Please see doc/driver-model/i2c-howto.rst for instructions. - */ - -#include <config.h> -#if defined(CONFIG_AT91FAMILY) -#include <asm/io.h> -#include <asm/arch/hardware.h> -#include <asm/arch/at91_pio.h> -#ifdef CONFIG_ATMEL_LEGACY -#include <asm/arch/gpio.h> -#endif -#endif -#include <i2c.h> -#include <linux/delay.h> - -#if defined(CONFIG_SOFT_I2C_GPIO_SCL) -# include <asm/gpio.h> - -# ifndef I2C_GPIO_SYNC -# define I2C_GPIO_SYNC -# endif - -# ifndef I2C_INIT -# define I2C_INIT \ - do { \ - gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \ - gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \ - } while (0) -# endif - -# ifndef I2C_ACTIVE -# define I2C_ACTIVE do { } while (0) -# endif - -# ifndef I2C_TRISTATE -# define I2C_TRISTATE do { } while (0) -# endif - -# ifndef I2C_READ -# define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA) -# endif - -# ifndef I2C_SDA -# define I2C_SDA(bit) \ - do { \ - if (bit) \ - gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \ - else \ - gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \ - I2C_GPIO_SYNC; \ - } while (0) -# endif - -# ifndef I2C_SCL -# define I2C_SCL(bit) \ - do { \ - gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \ - I2C_GPIO_SYNC; \ - } while (0) -# endif - -# ifndef I2C_DELAY -# define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */ -# endif - -#endif - -/* #define DEBUG_I2C */ - -#ifndef I2C_SOFT_DECLARATIONS -# define I2C_SOFT_DECLARATIONS -#endif - -/*----------------------------------------------------------------------- - * Definitions - */ -#define RETRIES 0 - -#define I2C_ACK 0 /* PD_SDA level to ack a byte */ -#define I2C_NOACK 1 /* PD_SDA level to noack a byte */ - -#ifdef DEBUG_I2C -#define PRINTD(fmt,args...) do { \ - printf (fmt ,##args); \ - } while (0) -#else -#define PRINTD(fmt,args...) -#endif - -/*----------------------------------------------------------------------- - * Local functions - */ -static void send_reset (void); -static void send_start (void); -static void send_stop (void); -static void send_ack (int); -static int write_byte (uchar byte); -static uchar read_byte (int); - -/*----------------------------------------------------------------------- - * Send a reset sequence consisting of 9 clocks with the data signal high - * to clock any confused device back into an idle state. Also send a - * <stop> at the end of the sequence for belts & suspenders. - */ -static void send_reset(void) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - int j; - - I2C_SCL(1); - I2C_SDA(1); -#ifdef I2C_INIT - I2C_INIT; -#endif - I2C_TRISTATE; - for(j = 0; j < 9; j++) { - I2C_SCL(0); - I2C_DELAY; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - } - send_stop(); - I2C_TRISTATE; -} - -/*----------------------------------------------------------------------- - * START: High -> Low on SDA while SCL is High - */ -static void send_start(void) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - - I2C_DELAY; - I2C_SDA(1); - I2C_ACTIVE; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_SDA(0); - I2C_DELAY; -} - -/*----------------------------------------------------------------------- - * STOP: Low -> High on SDA while SCL is High - */ -static void send_stop(void) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - - I2C_SCL(0); - I2C_DELAY; - I2C_SDA(0); - I2C_ACTIVE; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_SDA(1); - I2C_DELAY; - I2C_TRISTATE; -} - -/*----------------------------------------------------------------------- - * ack should be I2C_ACK or I2C_NOACK - */ -static void send_ack(int ack) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - - I2C_SCL(0); - I2C_DELAY; - I2C_ACTIVE; - I2C_SDA(ack); - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - I2C_SCL(0); - I2C_DELAY; -} - -/*----------------------------------------------------------------------- - * Send 8 bits and look for an acknowledgement. - */ -static int write_byte(uchar data) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - int j; - int nack; - - I2C_ACTIVE; - for(j = 0; j < 8; j++) { - I2C_SCL(0); - I2C_DELAY; - I2C_SDA(data & 0x80); - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - - data <<= 1; - } - - /* - * Look for an <ACK>(negative logic) and return it. - */ - I2C_SCL(0); - I2C_DELAY; - I2C_SDA(1); - I2C_TRISTATE; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - nack = I2C_READ; - I2C_SCL(0); - I2C_DELAY; - I2C_ACTIVE; - - return(nack); /* not a nack is an ack */ -} - -/*----------------------------------------------------------------------- - * if ack == I2C_ACK, ACK the byte so can continue reading, else - * send I2C_NOACK to end the read. - */ -static uchar read_byte(int ack) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - int data; - int j; - - /* - * Read 8 bits, MSB first. - */ - I2C_TRISTATE; - I2C_SDA(1); - data = 0; - for(j = 0; j < 8; j++) { - I2C_SCL(0); - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - data <<= 1; - data |= I2C_READ; - I2C_DELAY; - } - send_ack(ack); - - return(data); -} - -/*----------------------------------------------------------------------- - * Initialization - */ -static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) -{ - /* - * WARNING: Do NOT save speed in a static variable: if the - * I2C routines are called before RAM is initialized (to read - * the DIMM SPD, for instance), RAM won't be usable and your - * system will crash. - */ - send_reset (); -} - -/*----------------------------------------------------------------------- - * Probe to see if a chip is present. Also good for checking for the - * completion of EEPROM writes since the chip stops responding until - * the write completes (typically 10mSec). - */ -static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr) -{ - int rc; - - /* - * perform 1 byte write transaction with just address byte - * (fake write) - */ - send_start(); - rc = write_byte ((addr << 1) | 0); - send_stop(); - - return (rc ? 1 : 0); -} - -/*----------------------------------------------------------------------- - * Read bytes - */ -static int soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) -{ - int shift; - PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n", - chip, addr, alen, buffer, len); - -#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW - /* - * EEPROM chips that implement "address overflow" are ones - * like Catalyst 24WC04/08/16 which has 9/10/11 bits of - * address and the extra bits end up in the "chip address" - * bit slots. This makes a 24WC08 (1Kbyte) chip look like - * four 256 byte chips. - * - * Note that we consider the length of the address field to - * still be one byte because the extra address bits are - * hidden in the chip address. - */ - chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); - - PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n", - chip, addr); -#endif - - /* - * Do the addressing portion of a write cycle to set the - * chip's address pointer. If the address length is zero, - * don't do the normal write cycle to set the address pointer, - * there is no address pointer in this chip. - */ - send_start(); - if(alen > 0) { - if(write_byte(chip << 1)) { /* write cycle */ - send_stop(); - PRINTD("i2c_read, no chip responded %02X\n", chip); - return(1); - } - shift = (alen-1) * 8; - while(alen-- > 0) { - if(write_byte(addr >> shift)) { - PRINTD("i2c_read, address not <ACK>ed\n"); - return(1); - } - shift -= 8; - } - - /* Some I2C chips need a stop/start sequence here, - * other chips don't work with a full stop and need - * only a start. Default behaviour is to send the - * stop/start sequence. - */ -#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START - send_start(); -#else - send_stop(); - send_start(); -#endif - } - /* - * Send the chip address again, this time for a read cycle. - * Then read the data. On the last byte, we do a NACK instead - * of an ACK(len == 0) to terminate the read. - */ - write_byte((chip << 1) | 1); /* read cycle */ - while(len-- > 0) { - *buffer++ = read_byte(len == 0); - } - send_stop(); - return(0); -} - -/*----------------------------------------------------------------------- - * Write bytes - */ -static int soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) -{ - int shift, failures = 0; - - PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n", - chip, addr, alen, buffer, len); - - send_start(); - if(write_byte(chip << 1)) { /* write cycle */ - send_stop(); - PRINTD("i2c_write, no chip responded %02X\n", chip); - return(1); - } - shift = (alen-1) * 8; - while(alen-- > 0) { - if(write_byte(addr >> shift)) { - PRINTD("i2c_write, address not <ACK>ed\n"); - return(1); - } - shift -= 8; - } - - while(len-- > 0) { - if(write_byte(*buffer++)) { - failures++; - } - } - send_stop(); - return(failures); -} - -/* - * Register soft i2c adapters - */ -U_BOOT_I2C_ADAP_COMPLETE(soft00, soft_i2c_init, soft_i2c_probe, - soft_i2c_read, soft_i2c_write, NULL, - CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE, - 0) diff --git a/drivers/iommu/apple_dart.c b/drivers/iommu/apple_dart.c index bfd4ad20105..ebef28d0b9d 100644 --- a/drivers/iommu/apple_dart.c +++ b/drivers/iommu/apple_dart.c @@ -6,6 +6,7 @@ #include <cpu_func.h> #include <dm.h> #include <iommu.h> +#include <linux/sizes.h> #include <lmb.h> #include <memalign.h> #include <asm/io.h> diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index 5bbc18dfa51..a76f9e8d6bd 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -39,6 +39,9 @@ static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = { { "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, }, }; +static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev, + unsigned int opcode); + static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_plat *plat, u8 addr, u8 data) { @@ -155,8 +158,93 @@ static void sdhci_cdns_set_control_reg(struct sdhci_host *host) sdhci_cdns6_phy_adj(mmc->dev, plat, mmc->selected_mode); } +static __maybe_unused bool sdhci_cdns_sd_needs_tuning(struct mmc *mmc) +{ + struct sdhci_cdns_plat *plat = dev_get_plat(mmc->dev); + + if (!IS_SD(mmc)) + return false; + + if (!dev_read_bool(mmc->dev, "cdns,sd-hs-tuning")) + return false; + + /* Already tuned for this mode */ + if (plat->tuned_mode == mmc->selected_mode) + return false; + + switch (mmc->selected_mode) { + case SD_HS: + return mmc->bus_width == 4; + /* Add future modes here, e.g.: + * case UHS_SDR50: + * return true; + */ + default: + return false; + } +} + +static int sdhci_cdns_set_ios_post(struct sdhci_host *host) +{ + struct mmc *mmc = host->mmc; + struct sdhci_cdns_plat *plat = dev_get_plat(mmc->dev); + int ret __maybe_unused; + /* + * The SD6HC soft PHY requires runtime DLL delay calibration + * for SD High Speed mode. The default PHY_DLL_SLAVE_CTRL_REG + * values (READ_DQS_CMD_DELAY and READ_DQS_DELAY = 0) do not + * provide sufficient timing margin due to PVT and board trace + * variations. + * + * Tuning is performed once per entry into SD_HS mode + * (tracked by plat->tuned_mode state). The calibrated PHY delay + * values remain valid while the card stays in SD_HS mode, and + * leaving that tuned mode clears the state so re-entering SD_HS + * triggers tuning again. + * + * This must be done in set_ios_post (not set_control_reg) + * because the SDHCI controller must already be operating at + * the target bus width, clock, and speed mode before CMD19 + * tuning commands can succeed. + */ + + if (IS_ENABLED(CONFIG_MMC_SUPPORTS_TUNING)) { + if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_420 && + sdhci_cdns_sd_needs_tuning(mmc)) { + ret = sdhci_cdns_execute_tuning(mmc->dev, + MMC_CMD_SEND_TUNING_BLOCK); + if (ret) { + dev_err(mmc->dev, + "SD_HS tuning failed (ret=%d), using default PHY\n", + ret); + /* Restore default PHY settings and avoid retrying in this mode */ + sdhci_cdns6_phy_adj(mmc->dev, plat, + mmc->selected_mode); + plat->tuned_mode = mmc->selected_mode; + plat->tuned_dll_slave_ctrl = sdhci_cdns6_phy_get_dll_slave(plat); + return 0; + } + /* + * Tuning succeeded. The tuned_mode is already set by + * execute_tuning(), so the tuned value will be preserved + * across subsequent PHY reconfigurations. + */ + dev_dbg(mmc->dev, "SD_HS tuning successful\n"); + } + + /* Reset when mode changes away from a tuned mode */ + if (mmc->selected_mode != plat->tuned_mode) { + plat->tuned_mode = MMC_MODES_END; + plat->tuned_dll_slave_ctrl = 0; + } + } + + return 0; +} + static const struct sdhci_ops sdhci_cdns_ops = { .set_control_reg = sdhci_cdns_set_control_reg, + .set_ios_post = sdhci_cdns_set_ios_post, }; static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, @@ -204,6 +292,7 @@ static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev, int cur_streak = 0; int max_streak = 0; int end_of_streak = 0; + int ret; int i; /* @@ -229,7 +318,24 @@ static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev, return -EIO; } - return sdhci_cdns_set_tune_val(plat, end_of_streak - max_streak / 2); + ret = sdhci_cdns_set_tune_val(plat, end_of_streak - max_streak / 2); + if (ret) + return ret; + + /* + * Mark this mode as tuned. This is critical for both driver tuning + * (SD_HS via set_ios_post) and framework tuning (UHS_SDR104, MMC_HS_200, + * MMC_HS_400) so that subsequent PHY reconfigurations restore the + * calibrated DLL value instead of overwriting with DT defaults. + * + * For HS400, tuning is performed while the controller is in HS200 mode + * (mmc->selected_mode == MMC_HS_200 and mmc->hs400_tuning == true). + * Record the tuned mode as MMC_HS_400 so the calibrated DLL value is + * preserved across the HS200→HS400 transition. + */ + plat->tuned_mode = mmc->hs400_tuning ? MMC_HS_400 : mmc->selected_mode; + + return 0; } static struct dm_mmc_ops sdhci_cdns_mmc_ops; diff --git a/drivers/mmc/sdhci-cadence.h b/drivers/mmc/sdhci-cadence.h index 7101f00b75b..ea517491860 100644 --- a/drivers/mmc/sdhci-cadence.h +++ b/drivers/mmc/sdhci-cadence.h @@ -7,6 +7,8 @@ #ifndef SDHCI_CADENCE_H_ #define SDHCI_CADENCE_H_ +#include <mmc.h> + /* HRS - Host Register Set (specific to Cadence) */ /* PHY access port */ #define SDHCI_CDNS_HRS04 0x10 @@ -60,10 +62,13 @@ struct sdhci_cdns_plat { struct mmc_config cfg; struct mmc mmc; void __iomem *hrs_addr; + enum bus_mode tuned_mode; + u32 tuned_dll_slave_ctrl; }; int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 mode); int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat); int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val); +u32 sdhci_cdns6_phy_get_dll_slave(struct sdhci_cdns_plat *plat); #endif diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c index ca1086e2359..c8b42532e17 100644 --- a/drivers/mmc/sdhci-cadence6.c +++ b/drivers/mmc/sdhci-cadence6.c @@ -173,6 +173,30 @@ static void sdhci_cdns6_write_phy_reg(struct sdhci_cdns_plat *plat, u32 addr, u3 writel(val, plat->hrs_addr + SDHCI_CDNS_HRS05); } +static bool sdhci_cdns6_mode_is_tuned(struct sdhci_cdns_plat *plat, u32 mode) +{ + /* + * Check if the given mode has a valid tuned DLL value. + * Only modes that support tuning (driver or framework) can have + * valid tuned values. This prevents the initial state (tuned_mode=0) + * from falsely matching MMC_LEGACY. + */ + if (plat->tuned_mode != mode) + return false; + + switch (mode) { + case SD_HS: /* Driver tuning via set_ios_post */ + case UHS_SDR50: /* Future driver tuning support */ + case UHS_SDR104: /* Framework tuning */ + case MMC_HS_200: /* Framework tuning */ + case MMC_HS_400: /* Framework tuning */ + case MMC_HS_400_ES: /* Framework tuning */ + return true; + default: + return false; + } +} + static int sdhci_cdns6_reset_phy_dll(struct sdhci_cdns_plat *plat, bool reset) { void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS09; @@ -259,7 +283,18 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m sdhci_cdns6_write_phy_reg(plat, PHY_DQS_TIMING_REG_ADDR, sdhci_cdns6_phy_cfgs[0].val); sdhci_cdns6_write_phy_reg(plat, PHY_GATE_LPBK_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[1].val); sdhci_cdns6_write_phy_reg(plat, PHY_DLL_MASTER_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[4].val); - sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[2].val); + if (sdhci_cdns6_mode_is_tuned(plat, mode)) { + /* + * Use previously saved tuned DLL slave control value. + * Note: 0 is a valid tuned value (e.g., optimal tap at position 0), + * so we check both mode match AND that it's a tunable mode. + */ + sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, + plat->tuned_dll_slave_ctrl); + } else { + sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, + sdhci_cdns6_phy_cfgs[2].val); + } /* Switch Off the DLL Reset */ ret = sdhci_cdns6_reset_phy_dll(plat, false); @@ -318,6 +353,9 @@ int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val) sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, tmp); + /* Store tuned DLL slave control value which will be reapplied via set_ios(). */ + plat->tuned_dll_slave_ctrl = tmp; + /* Switch Off the DLL Reset */ ret = sdhci_cdns6_reset_phy_dll(plat, false); if (ret) { @@ -327,3 +365,8 @@ int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val) return 0; } + +u32 sdhci_cdns6_phy_get_dll_slave(struct sdhci_cdns_plat *plat) +{ + return sdhci_cdns6_read_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR); +} diff --git a/drivers/nvme/nvme-uclass.c b/drivers/nvme/nvme-uclass.c index 44c88ad27f3..4ab9567450f 100644 --- a/drivers/nvme/nvme-uclass.c +++ b/drivers/nvme/nvme-uclass.c @@ -44,7 +44,7 @@ UCLASS_DRIVER(nvme) = { .id = UCLASS_NVME, }; -struct bootdev_ops nvme_bootdev_ops = { +static const struct bootdev_ops nvme_bootdev_ops = { }; static const struct udevice_id nvme_bootdev_ids[] = { diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 2b14437f69c..0631b190b97 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -94,7 +94,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, *(prp_pool + i) = cpu_to_le64((ulong)prp_pool + page_size); i = 0; - prp_pool += page_size; + prp_pool = (u64 *)((uintptr_t)prp_pool + page_size); } *(prp_pool + i++) = cpu_to_le64(dma_addr); dma_addr += page_size; @@ -112,7 +112,10 @@ static __le16 nvme_get_cmd_id(void) { static unsigned short cmdid; - return cpu_to_le16((cmdid < USHRT_MAX) ? cmdid++ : 0); + if (cmdid >= USHRT_MAX) + cmdid = 0; + + return cpu_to_le16(cmdid++); } static u16 nvme_read_completion_status(struct nvme_queue *nvmeq, u16 index) diff --git a/drivers/nvme/nvme_apple.c b/drivers/nvme/nvme_apple.c index 7e7538553e3..e674eda8344 100644 --- a/drivers/nvme/nvme_apple.c +++ b/drivers/nvme/nvme_apple.c @@ -13,6 +13,7 @@ #include <asm/arch/rtkit.h> #include <asm/arch/sart.h> #include <linux/iopoll.h> +#include <linux/sizes.h> /* ASC registers */ #define REG_CPU_CTRL 0x0044 @@ -87,6 +88,9 @@ static int apple_nvme_setup_queue(struct nvme_queue *nvmeq) } priv->tcbs[nvmeq->qid] = (void *)memalign(4096, ANS_NVMMU_TCB_SIZE); + if (!priv->tcbs[nvmeq->qid]) + return -ENOMEM; + memset((void *)priv->tcbs[nvmeq->qid], 0, ANS_NVMMU_TCB_SIZE); switch (nvmeq->qid) { @@ -287,6 +291,7 @@ static const struct nvme_ops apple_nvme_ops = { }; static const struct udevice_id apple_nvme_ids[] = { + { .compatible = "apple,t8103-nvme-ans2" }, { .compatible = "apple,nvme-ans2" }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-apple.c b/drivers/pinctrl/pinctrl-apple.c index f373afde58e..083ea6d6cd5 100644 --- a/drivers/pinctrl/pinctrl-apple.c +++ b/drivers/pinctrl/pinctrl-apple.c @@ -192,6 +192,7 @@ static struct pinctrl_ops apple_pinctrl_ops = { }; static const struct udevice_id apple_pinctrl_ids[] = { + { .compatible = "apple,t8103-pinctrl" }, { .compatible = "apple,pinctrl" }, { /* sentinel */ } }; diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 012d7762384..4112b777371 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -98,6 +98,14 @@ config QCOM_RPMH_POWER_DOMAIN The RPMH power domain driver is responsible for managing power domains on Qualcomm SoCs. +config RENESAS_R8A78000_POWER_DOMAIN + bool "Enable the Renesas R-Car MDLC Power domain and reset driver" + depends on POWER_DOMAIN && ARCH_RENESAS + help + Enable support for Renesas R-Car R8A78000 X5H MDLC Power domain + and reset driver. The MDLC is responsible for managing both + power domains and resets on R-Car R8A78000 X5H SoC. + config SANDBOX_POWER_DOMAIN bool "Enable the sandbox power domain test driver" depends on POWER_DOMAIN && SANDBOX diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index f373fc01395..110153d5cf8 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o obj-$(CONFIG_MESON_SECURE_POWER_DOMAIN) += meson-secure-pwrc.o +obj-$(CONFIG_RENESAS_R8A78000_POWER_DOMAIN) += renesas-r8a78000-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o obj-$(CONFIG_SCMI_POWER_DOMAIN) += scmi-power-domain.o diff --git a/drivers/power/domain/apple-pmgr.c b/drivers/power/domain/apple-pmgr.c index 37fac815242..9873d3cd8db 100644 --- a/drivers/power/domain/apple-pmgr.c +++ b/drivers/power/domain/apple-pmgr.c @@ -110,6 +110,7 @@ static int apple_pmgr_of_xlate(struct power_domain *power_domain, } static const struct udevice_id apple_pmgr_ids[] = { + { .compatible = "apple,t8103-pmgr-pwrstate" }, { .compatible = "apple,pmgr-pwrstate" }, { /* sentinel */ } }; diff --git a/drivers/power/domain/renesas-r8a78000-power-domain.c b/drivers/power/domain/renesas-r8a78000-power-domain.c new file mode 100644 index 00000000000..d621373f90d --- /dev/null +++ b/drivers/power/domain/renesas-r8a78000-power-domain.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car Gen5 MDLC driver + * + * Copyright (C) 2026 Marek Vasut <[email protected]> + */ + +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <power-domain-uclass.h> +#include <reset-uclass.h> + +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> + +#include <dt-bindings/power/r8a78000-power-scmi.h> +#include <dt-bindings/reset/r8a78000-reset-scmi.h> + +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + +#define PKC_PROT_LOCK 0xa5a5a500 +#define PKC_PROT_UNLOCK 0xa5a5a501 + +#define MDLC_MSRESS_STANDBY 0 +#define MDLC_MSRESS_RESET 1 +#define MDLC_MSRESS_STOP 2 +#define MDLC_MSRESS_RUN 3 + +#define MDLC_MSRES00 0x900 +#define MDLC_MSRESS00 0x960 +#define MDLC_PKCPROT1 0xcf4 + +struct gen5_mdlc_priv { +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) + struct udevice *pd; +#endif +#if IS_ENABLED(CONFIG_RESET_SCMI) + struct udevice *rst; +#endif +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) || IS_ENABLED(CONFIG_RESET_SCMI) + u32 basever; +#endif +#if !IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) && !IS_ENABLED(CONFIG_RESET_SCMI) + void __iomem *base; +#endif +}; + +static int gen5_pd_of_xlate(struct power_domain *power_domain, + struct ofnode_phandle_args *args) +{ + /* Perform direct remap until the bindings stabilize. */ + power_domain->id = args->args[0]; + + return 0; +} + +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) +static int gen5_pd_on(struct power_domain *power_domain) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(power_domain->dev->parent); + struct power_domain_ops *ops = (struct power_domain_ops *)priv->pd->driver->ops; + struct power_domain scmi = { + .dev = priv->pd, + .id = power_domain->id + }; + + return ops->on(&scmi); +} + +static int gen5_pd_off(struct power_domain *power_domain) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(power_domain->dev->parent); + struct power_domain_ops *ops = (struct power_domain_ops *)priv->pd->driver->ops; + struct power_domain scmi = { + .dev = priv->pd, + .id = power_domain->id + }; + + return ops->off(&scmi); +} + +static const struct power_domain_ops pd_gen5_ops = { + .on = gen5_pd_on, + .off = gen5_pd_off, + .of_xlate = gen5_pd_of_xlate, +}; + +static int gen5_pd_probe(struct udevice *dev) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(dev->parent); + struct udevice *agent; + int ret; + + if (!priv->basever) { + ret = uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent); + if (ret) + return ret; + + if (!agent) + return -ENODEV; + + priv->basever = scmi_impl_version(agent); + } + + return uclass_get_device_by_driver(UCLASS_POWER_DOMAIN, + DM_DRIVER_GET(scmi_power_domain), + &priv->pd); +} + +U_BOOT_DRIVER(pd_gen5) = { + .name = "pd_gen5", + .id = UCLASS_POWER_DOMAIN, + .ops = &pd_gen5_ops, + .probe = gen5_pd_probe, + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; +#else +static const struct power_domain_ops pd_gen5_ops = { + .of_xlate = gen5_pd_of_xlate, +}; + +U_BOOT_DRIVER(pd_gen5) = { + .name = "pd_gen5", + .id = UCLASS_POWER_DOMAIN, + .ops = &pd_gen5_ops, + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; +#endif + +#if IS_ENABLED(CONFIG_RESET_SCMI) +static int gen5_reset_assert(struct reset_ctl *reset_ctl) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + struct reset_ops *ops = (struct reset_ops *)priv->rst->driver->ops; + struct reset_ctl scmi = { + .dev = priv->rst, + .id = reset_ctl->id + }; + + return ops->rst_assert(&scmi); +} + +static int gen5_reset_deassert(struct reset_ctl *reset_ctl) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + struct reset_ops *ops = (struct reset_ops *)priv->rst->driver->ops; + struct reset_ctl scmi = { + .dev = priv->rst, + .id = reset_ctl->id + }; + + return ops->rst_deassert(&scmi); +} + +struct rst_map_in { + u16 dt_id; /* DT binding clock ID */ + u16 fw_id; /* SCMI firmware clock ID */ +}; + +#define GEN5_SCMI_SDK_4_28 0x010a0000 +#define GEN5_SCMI_SDK_4_29 0x010b0000 +#define GEN5_SCMI_SDK_4_30 0x010c0000 +#define GEN5_SCMI_SDK_4_31 0x010d0000 +#define GEN5_SCMI_SDK_4_32 0x010e0000 + +static const struct rst_map_in gen5_rst_map_dt_sdk_4_28[] = { + { SCP_RESET_DOMAIN_ID_UFS0, 202 }, + { SCP_RESET_DOMAIN_ID_UFS1, 203 }, + { SCP_RESET_DOMAIN_ID_XPCS0, 316 }, + { SCP_RESET_DOMAIN_ID_XPCS1, 317 }, + { SCP_RESET_DOMAIN_ID_XPCS2, 318 }, + { SCP_RESET_DOMAIN_ID_XPCS3, 319 }, + { SCP_RESET_DOMAIN_ID_XPCS4, 320 }, + { SCP_RESET_DOMAIN_ID_XPCS5, 321 }, + { SCP_RESET_DOMAIN_ID_XPCS6, 322 }, + { SCP_RESET_DOMAIN_ID_XPCS7, 323 }, + { SCP_RESET_DOMAIN_ID_MPPHY01, 344 }, + { SCP_RESET_DOMAIN_ID_MPPHY11, 345 }, + { SCP_RESET_DOMAIN_ID_MPPHY21, 346 }, + { SCP_RESET_DOMAIN_ID_MPPHY31, 347 }, + { SCP_RESET_DOMAIN_ID_MPPHY02, 348 }, +}; + +static const struct rst_map_in gen5_rst_map_dt_sdk_4_31[] = { + { SCP_RESET_DOMAIN_ID_UFS0, 198 }, + { SCP_RESET_DOMAIN_ID_UFS1, 199 }, + { SCP_RESET_DOMAIN_ID_XPCS0, 312 }, + { SCP_RESET_DOMAIN_ID_XPCS1, 313 }, + { SCP_RESET_DOMAIN_ID_XPCS2, 314 }, + { SCP_RESET_DOMAIN_ID_XPCS3, 315 }, + { SCP_RESET_DOMAIN_ID_XPCS4, 316 }, + { SCP_RESET_DOMAIN_ID_XPCS5, 317 }, + { SCP_RESET_DOMAIN_ID_XPCS6, 318 }, + { SCP_RESET_DOMAIN_ID_XPCS7, 319 }, + { SCP_RESET_DOMAIN_ID_MPPHY01, 340 }, + { SCP_RESET_DOMAIN_ID_MPPHY11, 341 }, + { SCP_RESET_DOMAIN_ID_MPPHY21, 342 }, + { SCP_RESET_DOMAIN_ID_MPPHY31, 343 }, + { SCP_RESET_DOMAIN_ID_MPPHY02, 344 }, +}; + +static int gen5_reset_of_xlate(struct reset_ctl *reset_ctl, + struct ofnode_phandle_args *args) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const struct rst_map_in *map; + unsigned int map_size; + int i; + + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (priv->basever == GEN5_SCMI_SDK_4_28) { + map = gen5_rst_map_dt_sdk_4_28; + map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_28); + } else if (priv->basever == GEN5_SCMI_SDK_4_31 || + priv->basever == GEN5_SCMI_SDK_4_32) { + map = gen5_rst_map_dt_sdk_4_31; + map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_31); + } else { + printf("Unsupported SCMI base protocol version %x\n", priv->basever); + return -EINVAL; + } + + reset_ctl->id = -1; + for (i = 0; i < map_size; i++) { + if (map[i].dt_id != args->args[0]) + continue; + reset_ctl->id = map[i].fw_id; + break; + } + + return 0; +} + +static const struct reset_ops rst_gen5_ops = { + .rst_assert = gen5_reset_assert, + .rst_deassert = gen5_reset_deassert, + .of_xlate = gen5_reset_of_xlate, +}; + +static int gen5_rst_probe(struct udevice *dev) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(dev->parent); + struct udevice *agent; + int ret = 0; + + if (!priv->basever) { + ret = uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent); + if (ret) + return ret; + + if (!agent) + return -ENODEV; + + priv->basever = scmi_impl_version(agent); + } + + return uclass_get_device_by_driver(UCLASS_RESET, + DM_DRIVER_GET(scmi_reset_domain), + &priv->rst); +} +#else +static int mdlc_wait_for_reset(struct reset_ctl *reset_ctl) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const u32 offset = (reset_ctl->id / 16) * 4; + void __iomem *res = priv->base + MDLC_MSRES00 + offset; + void __iomem *stat = priv->base + MDLC_MSRESS00 + offset; + u32 val; + int ret; + + /* Wait 100ms for reset controller to synchronize. */ + ret = readl_poll_timeout(res, val, val == readl(stat), 100000); + if (ret < 0) + dev_err(reset_ctl->dev, "Reset controller out of sync!\n"); + + return ret; +} + +static void mdlc_rmw_msres(struct reset_ctl *reset_ctl, const int val) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const u32 offset = (reset_ctl->id / 16) * 4; + const u32 mask = 3 << ((reset_ctl->id % 16) * 2); + void __iomem *prot = priv->base + MDLC_PKCPROT1; + void __iomem *res = priv->base + MDLC_MSRES00 + offset; + u32 reg; + + reg = readl(res); + reg &= ~mask; + reg |= field_prep(mask, val); + + writel(PKC_PROT_UNLOCK, prot); + writel(reg, res); + writel(PKC_PROT_LOCK, prot); +} + +static int gen5_reset_toggle(struct reset_ctl *reset_ctl, const u8 step1, + const u8 step2, const u8 step3, const u8 step4) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const u32 offset = (reset_ctl->id / 16) * 4; + const u32 mask = 3 << ((reset_ctl->id % 16) * 2); + void __iomem *stat = priv->base + MDLC_MSRESS00 + offset; + u32 status; + int ret; + + ret = mdlc_wait_for_reset(reset_ctl); + if (ret) + return ret; + + status = field_get(mask, readl(stat)); + if (status == step1) { + mdlc_rmw_msres(reset_ctl, step2); + ret = mdlc_wait_for_reset(reset_ctl); + if (ret) + return ret; + status = field_get(mask, readl(stat)); + } + + if (status == step2 || status == step3) { + mdlc_rmw_msres(reset_ctl, step4); + ret = mdlc_wait_for_reset(reset_ctl); + if (ret) + return ret; + } + + return 0; +} + +static int gen5_reset_assert(struct reset_ctl *reset_ctl) +{ + return gen5_reset_toggle(reset_ctl, + MDLC_MSRESS_STOP, MDLC_MSRESS_STANDBY, + MDLC_MSRESS_RUN, MDLC_MSRESS_RESET); +} + +static int gen5_reset_deassert(struct reset_ctl *reset_ctl) +{ + return gen5_reset_toggle(reset_ctl, + MDLC_MSRESS_STANDBY, MDLC_MSRESS_RESET, + MDLC_MSRESS_STOP, MDLC_MSRESS_RUN); +} + +static int gen5_reset_of_xlate(struct reset_ctl *reset_ctl, + struct ofnode_phandle_args *args) +{ + /* Perform direct remap until the bindings stabilize. */ + reset_ctl->id = args->args[0]; + + return 0; +} + +static const struct reset_ops rst_gen5_ops = { + .rst_assert = gen5_reset_assert, + .rst_deassert = gen5_reset_deassert, + .of_xlate = gen5_reset_of_xlate, +}; + +static int gen5_rst_probe(struct udevice *dev) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(dev->parent); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + return 0; +} +#endif + +U_BOOT_DRIVER(rst_gen5) = { + .name = "rst_gen5", + .id = UCLASS_RESET, + .ops = &rst_gen5_ops, + .probe = gen5_rst_probe, + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; + +int gen5_mdlc_bind(struct udevice *parent) +{ + struct udevice *pdev, *rdev; + struct driver *pdrv, *rdrv; + int ret; + + pdrv = lists_driver_lookup_name("pd_gen5"); + if (!pdrv) + return -ENOENT; + + rdrv = lists_driver_lookup_name("rst_gen5"); + if (!rdrv) + return -ENOENT; + + ret = device_bind_with_driver_data(parent, pdrv, "pd_gen5", 0, + dev_ofnode(parent), &pdev); + if (ret) + return ret; + + ret = device_bind_with_driver_data(parent, rdrv, "rst_gen5", (ulong)pdev, + dev_ofnode(parent), &rdev); + if (ret) + device_unbind(pdev); + + return ret; +} + +static const struct udevice_id r8a78000_mdlc_ids[] = { + { .compatible = "renesas,r8a78000-mdlc", }, + { } +}; + +U_BOOT_DRIVER(mdlc_gen5) = { + .name = "mdlc_gen5", + .id = UCLASS_NOP, + .of_match = r8a78000_mdlc_ids, + .bind = gen5_mdlc_bind, + .priv_auto = sizeof(struct gen5_mdlc_priv), +}; diff --git a/drivers/reset/stm32/stm32-reset-mp21.c b/drivers/reset/stm32/stm32-reset-mp21.c index 7d169d7582f..0e92b0f5d5d 100644 --- a/drivers/reset/stm32/stm32-reset-mp21.c +++ b/drivers/reset/stm32/stm32-reset-mp21.c @@ -5,7 +5,7 @@ */ #include <dm.h> -#include <stm32-reset-core.h> +#include "stm32-reset-core.h" #include <stm32mp21_rcc.h> #include <dt-bindings/reset/st,stm32mp21-rcc.h> diff --git a/drivers/spi/apple_spi.c b/drivers/spi/apple_spi.c index acb74886708..acc87ea7bdc 100644 --- a/drivers/spi/apple_spi.c +++ b/drivers/spi/apple_spi.c @@ -270,6 +270,7 @@ static int apple_spi_probe(struct udevice *dev) } static const struct udevice_id apple_spi_of_match[] = { + { .compatible = "apple,t8103-spi" }, { .compatible = "apple,spi" }, { /* sentinel */ } }; diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index 117e36376b7..c5bc603b5c0 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -216,13 +216,13 @@ int espi_xfer(struct fsl_spi_slave *fsl, uint cs, unsigned int bitlen, break; case SPI_XFER_BEGIN | SPI_XFER_END: len = data_len; - buffer = (unsigned char *)malloc(len * 2); + buffer = (unsigned char *)malloc(len); if (!buffer) { debug("SF: Failed to malloc memory.\n"); return 1; } memcpy(buffer, data_out, len); - rx_offset = len; + rx_offset = 0; cmd_len = 0; break; } @@ -275,7 +275,7 @@ int espi_xfer(struct fsl_spi_slave *fsl, uint cs, unsigned int bitlen, } } if (data_in) { - memcpy(data_in, buffer + rx_offset, tran_len); + memcpy(data_in, buffer + 2 * cmd_len, tran_len); if (*buffer == 0x0b) { data_in += tran_len; data_len -= tran_len; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index f7a92ded6da..a2eee2bca2c 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -289,10 +289,6 @@ static int usba_ep_disable(struct usb_ep *_ep) if (!ep->desc) { spin_unlock_irqrestore(&udc->lock, flags); - /* REVISIT because this driver disables endpoints in - * reset_all_endpoints() before calling disconnect(), - * most gadget drivers would trigger this non-error ... - */ if (udc->gadget.speed != USB_SPEED_UNKNOWN) DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name); @@ -571,20 +567,6 @@ static void reset_all_endpoints(struct usba_udc *udc) list_del_init(&req->queue); request_complete(ep, req, -ECONNRESET); } - - /* NOTE: normally, the next call to the gadget driver is in - * charge of disabling endpoints... usually disconnect(). - * The exception would be entering a high speed test mode. - * - * FIXME remove this code ... and retest thoroughly. - */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - spin_unlock(&udc->lock); - usba_ep_disable(&ep->ep); - spin_lock(&udc->lock); - } - } } static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 8f7256069f5..b6c11d97a62 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -548,13 +548,11 @@ static int acm_add(struct usb_configuration *c) status = udc_device_get_by_index(0, &f_acm->udc); if (status) - return status; + goto err; status = usb_add_function(c, &f_acm->usb_function); - if (status) { - free(f_acm); - return status; - } + if (status) + goto err; buf_init(&f_acm->rx_buf, 2048); buf_init(&f_acm->tx_buf, 2048); @@ -562,6 +560,10 @@ static int acm_add(struct usb_configuration *c) if (!default_acm_function) default_acm_function = f_acm; + return 0; + +err: + free(f_acm); return status; } diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c index 94968ef1c75..404d9140cb2 100644 --- a/drivers/virtio/virtio_blk.c +++ b/drivers/virtio/virtio_blk.c @@ -13,6 +13,7 @@ #include <virtio.h> #include <virtio_ring.h> #include <linux/log2.h> +#include <linux/err.h> #include "virtio_blk.h" #include <malloc.h> @@ -181,7 +182,7 @@ static ulong virtio_blk_do_req(struct udevice *dev, u64 sector, ret = virtio_blk_do_single_req(dev, sector + i, blk_per_sg, buffer + i * 512, type); - if (ret < 0) + if (IS_ERR_VALUE(ret)) return ret; i += blk_per_sg; } diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c index c7307f41cb7..9e998994216 100644 --- a/drivers/watchdog/apple_wdt.c +++ b/drivers/watchdog/apple_wdt.c @@ -78,6 +78,7 @@ static const struct wdt_ops apple_wdt_ops = { }; static const struct udevice_id apple_wdt_ids[] = { + { .compatible = "apple,t8103-wdt" }, { .compatible = "apple,wdt" }, { /* sentinel */ } }; |
