[PATCH v1 0/2] Introduce Meson SM driver
Hello! This patchset adds Meson Secure Monitor driver, which export following generic API: - sm_call_read() - sm_call_write() - sm_call() Also, now use this new API in arch/arm/mach-meson/sm.c helper functions. Alexey Romanov (2): drivers: firmware: introduce Meson Secure Monitor driver asm/arch: mach-meson: use secure monitor driver arch/arm/mach-meson/Kconfig | 1 + arch/arm/mach-meson/sm.c | 161 +- drivers/firmware/Kconfig | 10 ++ drivers/firmware/Makefile | 1 + drivers/firmware/meson/Kconfig| 6 + drivers/firmware/meson/Makefile | 3 + drivers/firmware/meson/meson_sm.c | 217 ++ include/meson/sm_handle.h | 38 ++ 8 files changed, 373 insertions(+), 64 deletions(-) create mode 100644 drivers/firmware/meson/Kconfig create mode 100644 drivers/firmware/meson/Makefile create mode 100644 drivers/firmware/meson/meson_sm.c create mode 100644 include/meson/sm_handle.h -- 2.38.1
[PATCH v1 1/2] drivers: firmware: introduce Meson Secure Monitor driver
At the moment, only smc API is a set of functions in arch/arm/mach-meson/sm.c. This approach is hard to configure and also doesn't contain any generic API for calling smc. This patch add Meson SM driver with generic API (struct meson_sm_ops): - sm_call() - sm_call_write() - sm_call_read() A typical driver usage example is shown here: 1. uclass_get_device_by_driver(UCLASS_FIRMWARE, "secure-monitor", &dev); 2. handle = meson_sm_get_handle(dev); 3. handle->ops.sm_call(dev, cmd, ...); Signed-off-by: Alexey Romanov --- arch/arm/mach-meson/Kconfig | 1 + drivers/firmware/Kconfig | 10 ++ drivers/firmware/Makefile | 1 + drivers/firmware/meson/Kconfig| 6 + drivers/firmware/meson/Makefile | 3 + drivers/firmware/meson/meson_sm.c | 217 ++ include/meson/sm_handle.h | 38 ++ 7 files changed, 276 insertions(+) create mode 100644 drivers/firmware/meson/Kconfig create mode 100644 drivers/firmware/meson/Makefile create mode 100644 drivers/firmware/meson/meson_sm.c create mode 100644 include/meson/sm_handle.h diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 669ca09a00a..b8746d27f63 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -11,6 +11,7 @@ config MESON64_COMMON select PWRSEQ select MMC_PWRSEQ select BOARD_LATE_INIT + select MESON_FIRMWARE imply CMD_DM config MESON_GX diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index eae1c8ddc9f..17b70fdea6d 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -37,6 +37,15 @@ config ZYNQMP_FIRMWARE Say yes to enable ZynqMP firmware interface driver. If in doubt, say N. +config MESON_FIRMWARE + bool "Meson Firmware interface" + select FIRMWARE + help + This option enables Meson firmware interface, + which is used by different drivers to communicate + with the firmware for various platform management + services. + config ARM_SMCCC_FEATURES bool "Arm SMCCC features discovery" depends on ARM_PSCI_FW @@ -45,4 +54,5 @@ config ARM_SMCCC_FEATURES the PSCI driver is always probed and binds dirvers registered to the Arm SMCCC services if any and reported as supported by the SMCCC firmware. +source "drivers/firmware/meson/Kconfig" source "drivers/firmware/scmi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 7ce83d72bd3..a6300be27ad 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_SANDBOX) += firmware-sandbox.o obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware-zynqmp.o obj-$(CONFIG_SCMI_FIRMWARE)+= scmi/ +obj-$(CONFIG_MESON_FIRMWARE) += meson/ diff --git a/drivers/firmware/meson/Kconfig b/drivers/firmware/meson/Kconfig new file mode 100644 index 000..0fd4f3251e1 --- /dev/null +++ b/drivers/firmware/meson/Kconfig @@ -0,0 +1,6 @@ +config MESON_SM + bool "Amlogic Secure Monitor driver" + depends on ARCH_MESON + default y + help + Say y here to enable the Amlogic secure monitor driver. diff --git a/drivers/firmware/meson/Makefile b/drivers/firmware/meson/Makefile new file mode 100644 index 000..b5d26f150b0 --- /dev/null +++ b/drivers/firmware/meson/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_MESON_SM) += meson_sm.o diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c new file mode 100644 index 000..28eacb89810 --- /dev/null +++ b/drivers/firmware/meson/meson_sm.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct meson_sm_cmd { + u32 smc_id; +}; + +#define SET_CMD(index, id) \ + [index] = { \ + .smc_id = id, \ + } + +struct meson_sm_data { + u32 cmd_get_shmem_in; + u32 cmd_get_shmem_out; + unsigned int shmem_size; + struct meson_sm_cmd cmd[]; +}; + +struct meson_sm_priv { + void *sm_shmem_in; + void *sm_shmem_out; + struct meson_sm_handle handle; + const struct meson_sm_data *data; +}; + +static unsigned long __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2, + u32 arg3, u32 arg4) +{ + struct pt_regs r; + + r.regs[0] = cmd; + r.regs[1] = arg0; + r.regs[2] = arg1; + r.regs[3] = arg2; + r.regs[4] = arg3; + r.regs[5] = arg4; + + smc_call(&r); + + return r.regs[0]; +}; + +static u32 meson_sm_get_cmd(const struct meson_sm_data *data, +
[PATCH v1 2/2] asm/arch: mach-meson: use secure monitor driver
Now we have to use UCLASS_FIRMWARE meson secure monitor driver instead of raw smc_call() function call. Signed-off-by: Alexey Romanov --- arch/arm/mach-meson/sm.c | 161 +++ 1 file changed, 97 insertions(+), 64 deletions(-) diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index d600c64d0be..347ff448f79 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -16,72 +16,74 @@ #include #include #include +#include #include #include -#define FN_GET_SHARE_MEM_INPUT_BASE0x8220 -#define FN_GET_SHARE_MEM_OUTPUT_BASE 0x8221 -#define FN_EFUSE_READ 0x8230 -#define FN_EFUSE_WRITE 0x8231 -#define FN_CHIP_ID 0x8244 -#define FN_PWRDM_SET 0x8293 - -static void *shmem_input; -static void *shmem_output; - -static void meson_init_shmem(void) +static inline struct udevice *meson_get_sm_device(void) { - struct pt_regs regs; - - if (shmem_input && shmem_output) - return; + struct udevice *dev; + int err; - regs.regs[0] = FN_GET_SHARE_MEM_INPUT_BASE; - smc_call(®s); - shmem_input = (void *)regs.regs[0]; - - regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE; - smc_call(®s); - shmem_output = (void *)regs.regs[0]; + err = uclass_get_device_by_name(UCLASS_FIRMWARE, "secure-monitor", &dev); + if (err) { + pr_err("Mesom SM device not found\n"); + return ERR_PTR(err); + } - debug("Secure Monitor shmem: 0x%p 0x%p\n", shmem_input, shmem_output); + return dev; } ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size) { - struct pt_regs regs; - - meson_init_shmem(); - - regs.regs[0] = FN_EFUSE_READ; - regs.regs[1] = offset; - regs.regs[2] = size; - - smc_call(®s); - - if (regs.regs[0] == 0) - return -1; + struct meson_sm_handle *handle; + struct udevice *dev; + int err; + + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + handle = meson_sm_get_handle(dev); + if (IS_ERR(handle)) { + pr_err("Failed to get Meson SM handle\n"); + return PTR_ERR(handle); + } - memcpy(buffer, shmem_output, min(size, regs.regs[0])); + err = handle->ops.sm_call_read(dev, buffer, size, + MESON_SMC_CMD_EFUSE_READ, offset, size); + if (err < 0) { + pr_err("Failed to read efuse memory (%d)\n", err); + return err; + } - return regs.regs[0]; + return err; } ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size) { - struct pt_regs regs; - - meson_init_shmem(); - -memcpy(shmem_input, buffer, size); - - regs.regs[0] = FN_EFUSE_WRITE; - regs.regs[1] = offset; - regs.regs[2] = size; + struct meson_sm_handle *handle; + struct udevice *dev; + int err; + + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + handle = meson_sm_get_handle(dev); + if (IS_ERR(handle)) { + pr_err("Failed to get Meson SM handle\n"); + return PTR_ERR(handle); + } - smc_call(®s); + err = handle->ops.sm_call_write(dev, buffer, size, + MESON_SMC_CMD_EFUSE_WRITE, offset, size); + if (err < 0) { + pr_err("Failed to write efuse memory (%d)\n", err); + return err; + } - return regs.regs[0]; + return err; } #define SM_CHIP_ID_LENGTH 119 @@ -90,18 +92,35 @@ ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size) int meson_sm_get_serial(void *buffer, size_t size) { - struct pt_regs regs; - - meson_init_shmem(); + struct meson_sm_handle *handle; + struct udevice *dev; + u8 *id_buffer; + int err; + + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + handle = meson_sm_get_handle(dev); + if (IS_ERR(handle)) { + pr_err("Failed to get Meson SM handle\n"); + return PTR_ERR(handle); + } - regs.regs[0] = FN_CHIP_ID; - regs.regs[1] = 0; - regs.regs[2] = 0; + id_buffer = malloc(sizeof(u8) * SM_CHIP_ID_LENGTH); + if (!id_buffer) + return -ENOMEM; - smc_call(®s); + err = handle->ops.sm_call_read(dev, id_buffer, SM_CHIP_ID_LENGTH, + MESON_SMC_CMD_CHIP_ID_GET, 0, 0); + if (err < 0) { + pr_err("Failed to read serial number (%d)\n", err); + free(id_buffer); + return err;
Re: [PATCH v1 1/2] drivers: firmware: introduce Meson Secure Monitor driver
Hello, Simon! On Thu, Jul 06, 2023 at 09:58:02AM -0600, Simon Glass wrote: > Hi Alexey, > > On Thu, 6 Jul 2023 at 14:16, Alexey Romanov wrote: > > > > At the moment, only smc API is a set of functions in > > arch/arm/mach-meson/sm.c. This approach is hard to configure > > and also doesni't contain any generic API for calling smc. > > > > This patch add Meson SM driver with generic API (struct meson_sm_ops): > > > > - sm_call() > > - sm_call_write() > > - sm_call_read() > > > > A typical driver usage example is shown here: > > > > 1. uclass_get_device_by_driver(UCLASS_FIRMWARE, "secure-monitor", &dev); > > 2. handle = meson_sm_get_handle(dev); > > 3. handle->ops.sm_call(dev, cmd, ...); > > > > Signed-off-by: Alexey Romanov > > --- > > arch/arm/mach-meson/Kconfig | 1 + > > drivers/firmware/Kconfig | 10 ++ > > drivers/firmware/Makefile | 1 + > > drivers/firmware/meson/Kconfig| 6 + > > drivers/firmware/meson/Makefile | 3 + > > drivers/firmware/meson/meson_sm.c | 217 ++ > > include/meson/sm_handle.h | 38 ++ > > 7 files changed, 276 insertions(+) > > create mode 100644 drivers/firmware/meson/Kconfig > > create mode 100644 drivers/firmware/meson/Makefile > > create mode 100644 drivers/firmware/meson/meson_sm.c > > create mode 100644 include/meson/sm_handle.h > > Please can you use the remoteproc uclass for this and add a proper driver? > I don't see it architecturally well. Can you explain please? This driver is just ARM SMC fw interface. There seems to be nothing to do here for remoteproc uclass. > Regards, > SImon -- Thank you, Alexey
Re: [PATCH v1 1/2] drivers: firmware: introduce Meson Secure Monitor driver
Hello! On Fri, Jul 07, 2023 at 11:35:47AM -0600, Simon Glass wrote: > Hi Alexey, > > On Fri, 7 Jul 2023 at 09:43, Alexey Romanov wrote: > > > > Hello, Simon! > > > > On Thu, Jul 06, 2023 at 09:58:02AM -0600, Simon Glass wrote: > > > Hi Alexey, > > > > > > On Thu, 6 Jul 2023 at 14:16, Alexey Romanov > > > wrote: > > > > > > > > At the moment, only smc API is a set of functions in > > > > arch/arm/mach-meson/sm.c. This approach is hard to configure > > > > and also doesni't contain any generic API for calling smc. > > > > > > > > This patch add Meson SM driver with generic API (struct meson_sm_ops): > > > > > > > > - sm_call() > > > > - sm_call_write() > > > > - sm_call_read() > > > > > > > > A typical driver usage example is shown here: > > > > > > > > 1. uclass_get_device_by_driver(UCLASS_FIRMWARE, "secure-monitor", &dev); > > > > 2. handle = meson_sm_get_handle(dev); > > > > 3. handle->ops.sm_call(dev, cmd, ...); > > > > > > > > Signed-off-by: Alexey Romanov > > > > --- > > > > arch/arm/mach-meson/Kconfig | 1 + > > > > drivers/firmware/Kconfig | 10 ++ > > > > drivers/firmware/Makefile | 1 + > > > > drivers/firmware/meson/Kconfig| 6 + > > > > drivers/firmware/meson/Makefile | 3 + > > > > drivers/firmware/meson/meson_sm.c | 217 ++ > > > > include/meson/sm_handle.h | 38 ++ > > > > 7 files changed, 276 insertions(+) > > > > create mode 100644 drivers/firmware/meson/Kconfig > > > > create mode 100644 drivers/firmware/meson/Makefile > > > > create mode 100644 drivers/firmware/meson/meson_sm.c > > > > create mode 100644 include/meson/sm_handle.h > > > > > > Please can you use the remoteproc uclass for this and add a proper driver? > > > > > > > I don't see it architecturally well. Can you explain please? > > > > This driver is just ARM SMC fw interface. There seems to be nothing to > > do here for remoteproc uclass. > > Well you seem to be implementing a remote CPU interface, which is what > remoteproc is for. How does Linux do this? The main idea of the patchset is to abstract the smc calls (which run on the same CPU) and make a request to the firmware that runs on a higher EL. UCLASS_REMOTEPROC may give the impression that we are interacting with another CPU, although this is not the case. Also, UCLASS_REMOTEPROC requires two mandatory interfaces: load() and start(), and I don't even know how to apply my current changes to them. My implementation is very close to the Linux implementation, they also use the firmware driver without remoteproc: https://elixir.bootlin.com/linux/latest/source/drivers/firmware/meson/meson_sm.c I spoke to Neil on IRC and he said UCLASS_FIRMWARE for such driver is OK. > > Also there is a pending series on FFA - is that related? It uses smc > from what I can tell. Not entirely clear, my changes don't seem to be related to this patchset. > > Regards, > Simon -- Thank you, Alexey
Re: [PATCH v1 1/2] drivers: firmware: introduce Meson Secure Monitor driver
Hi Simon, On Mon, Jul 10, 2023 at 01:45:53PM -0600, Simon Glass wrote: > Hi Alexey, > > On Mon, 10 Jul 2023 at 02:34, Alexey Romanov wrote: > > > > > > Hello! > > > > On Fri, Jul 07, 2023 at 11:35:47AM -0600, Simon Glass wrote: > > > Hi Alexey, > > > > > > On Fri, 7 Jul 2023 at 09:43, Alexey Romanov > > > wrote: > > > > > > > > Hello, Simon! > > > > > > > > On Thu, Jul 06, 2023 at 09:58:02AM -0600, Simon Glass wrote: > > > > > Hi Alexey, > > > > > > > > > > On Thu, 6 Jul 2023 at 14:16, Alexey Romanov > > > > > wrote: > > > > > > > > > > > > At the moment, only smc API is a set of functions in > > > > > > arch/arm/mach-meson/sm.c. This approach is hard to configure > > > > > > and also doesni't contain any generic API for calling smc. > > > > > > > > > > > > This patch add Meson SM driver with generic API (struct > > > > > > meson_sm_ops): > > > > > > > > > > > > - sm_call() > > > > > > - sm_call_write() > > > > > > - sm_call_read() > > > > > > > > > > > > A typical driver usage example is shown here: > > > > > > > > > > > > 1. uclass_get_device_by_driver(UCLASS_FIRMWARE, "secure-monitor", > > > > > > &dev); > > > > > > 2. handle = meson_sm_get_handle(dev); > > > > > > 3. handle->ops.sm_call(dev, cmd, ...); > > > > > > > > > > > > Signed-off-by: Alexey Romanov > > > > > > --- > > > > > > arch/arm/mach-meson/Kconfig | 1 + > > > > > > drivers/firmware/Kconfig | 10 ++ > > > > > > drivers/firmware/Makefile | 1 + > > > > > > drivers/firmware/meson/Kconfig| 6 + > > > > > > drivers/firmware/meson/Makefile | 3 + > > > > > > drivers/firmware/meson/meson_sm.c | 217 > > > > > > ++ > > > > > > include/meson/sm_handle.h | 38 ++ > > > > > > 7 files changed, 276 insertions(+) > > > > > > create mode 100644 drivers/firmware/meson/Kconfig > > > > > > create mode 100644 drivers/firmware/meson/Makefile > > > > > > create mode 100644 drivers/firmware/meson/meson_sm.c > > > > > > create mode 100644 include/meson/sm_handle.h > > > > > > > > > > Please can you use the remoteproc uclass for this and add a proper > > > > > driver? > > > > > > > > > > > > > I don't see it architecturally well. Can you explain please? > > > > > > > > This driver is just ARM SMC fw interface. There seems to be nothing to > > > > do here for remoteproc uclass. > > > > > > Well you seem to be implementing a remote CPU interface, which is what > > > remoteproc is for. How does Linux do this? > > > > The main idea of the patchset is to abstract the smc calls (which run on > > the same CPU) and make a request to the firmware that runs on a higher > > EL. UCLASS_REMOTEPROC may give the impression that we are > > interacting with another CPU, although this is not the case. > > > > Also, UCLASS_REMOTEPROC requires two mandatory interfaces: load() and > > start(), and I don't even know how to apply my current changes to them. > > You can return -ENOSYS if not implemented. > > > > > My implementation is very close to the Linux implementation, they > > also use the firmware driver without remoteproc: > > > > https://elixir.bootlin.com/linux/latest/source/drivers/firmware/meson/meson_sm.c > > Yes that seems like it doesn't use any common infra. I don't think it > is a great model for U-Boot though. > > > > > I spoke to Neil on IRC and he said UCLASS_FIRMWARE for such driver is > > OK. > > > > > > > > Also there is a pending series on FFA - is that related? It uses smc > > > from what I can tell. > > > > Not entirely clear, my changes don't seem to be related to this > > patchset. > > So perhaps this needs a new UCLASS_SMC? I see various other SMC calls > in U-Boot but no one has taken the initiative to think about this in > terms of driver model. What will be the feature of this uclass? If it's just us adding a new uclass with a different name... Don't know if that makes amy sense? Then the difference between UCLASS_SMC and UCLASS_FIRMWARE will be only in the name. > > It might just need one operation, to make a call, passing a regs > struct, perhaps? The uclass would presumably be ARM-specific. > > I really don't think this is UCLASS_FIRMWARE. That seems to be for > loading firmware. It doesn't even have a firmware.h header. I see what drivers/firmware/psci.c is UCLASS_FIRMWARE and also use smc_call() function. Or firmware-zynqmo.c. In this case, we then have to convert them to UCLASS_SMC in the same way? It seemed to me that UCLASS_FIRMWARE is a SoC(arch)-specific driver that can work with any interface. > > Also instead of: > > 1. uclass_get_device_by_driver(UCLASS_FIRMWARE, "secure-monitor", &dev); > > use: > > ret = uclass_first_device_err(UCLASS_SMC, &dev) > > using device tree to find the device. > > Regards, > Simon -- Thank you, Alexey
[PATCH v3 0/1] hwrng: meson - add support for S4
Hello! This patch adds support for Meson S4 series hardware number generator using new algo. V2: - Sync with Linux version. V3: - Fix compiler warning "makes pointer from integer without a cast" Alexey Romanov (1): drivers: rng: add support for Meson S4 drivers/rng/meson-rng.c | 72 - 1 file changed, 71 insertions(+), 1 deletion(-) -- 2.25.1
[PATCH v3 1/1] drivers: rng: add support for Meson S4
For some Amlogic SOC's, mechanism to obtain random number has been changed. For example, S4 now uses status bit waiting algo. Signed-off-by: Alexey Romanov --- drivers/rng/meson-rng.c | 72 - 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/rng/meson-rng.c b/drivers/rng/meson-rng.c index e0a1e8c7e0..fd2988e91b 100644 --- a/drivers/rng/meson-rng.c +++ b/drivers/rng/meson-rng.c @@ -10,10 +10,23 @@ #include #include #include +#include + +#define RNG_DATA 0x00 +#define RNG_S4_DATA0x08 +#define RNG_S4_CFG 0x00 + +#define RUN_BITBIT(0) +#define SEED_READY_STS_BIT BIT(31) + +struct meson_rng_priv { + u32 (*read)(fdt_addr_t base); +}; struct meson_rng_plat { fdt_addr_t base; struct clk clk; + struct meson_rng_priv *priv; }; /** @@ -27,10 +40,11 @@ struct meson_rng_plat { static int meson_rng_read(struct udevice *dev, void *data, size_t len) { struct meson_rng_plat *pdata = dev_get_plat(dev); + struct meson_rng_priv *priv = pdata->priv; char *buffer = (char *)data; while (len) { - u32 rand = readl(pdata->base); + u32 rand = priv->read(pdata->base); size_t step; if (len >= 4) @@ -44,6 +58,47 @@ static int meson_rng_read(struct udevice *dev, void *data, size_t len) return 0; } +static int meson_rng_wait_status(void __iomem *cfg_addr, int bit) +{ + u32 status = 0; + int ret; + + ret = readl_relaxed_poll_timeout(cfg_addr, +status, !(status & bit), +1); + if (ret) + return -EBUSY; + + return 0; +} + +static u32 meson_common_rng_read(fdt_addr_t base) +{ + return readl(base); +} + +static u32 meson_s4_rng_read(fdt_addr_t base) +{ + void __iomem *cfg_addr = (void *)base + RNG_S4_CFG; + int err; + + writel_relaxed(readl_relaxed(cfg_addr) | SEED_READY_STS_BIT, cfg_addr); + + err = meson_rng_wait_status(cfg_addr, SEED_READY_STS_BIT); + if (err) { + pr_err("Seed isn't ready, try again\n"); + return err; + } + + err = meson_rng_wait_status(cfg_addr, RUN_BIT); + if (err) { + pr_err("Can't get random number, try again\n"); + return err; + } + + return readl_relaxed(base + RNG_S4_DATA); +} + /** * meson_rng_probe() - probe rng device * @@ -59,6 +114,8 @@ static int meson_rng_probe(struct udevice *dev) if (err) return err; + pdata->priv = (struct meson_rng_priv *)dev_get_driver_data(dev); + return 0; } @@ -102,9 +159,22 @@ static const struct dm_rng_ops meson_rng_ops = { .read = meson_rng_read, }; +static const struct meson_rng_priv meson_rng_priv = { + .read = meson_common_rng_read, +}; + +static const struct meson_rng_priv meson_rng_priv_s4 = { + .read = meson_s4_rng_read, +}; + static const struct udevice_id meson_rng_match[] = { { .compatible = "amlogic,meson-rng", + .data = (ulong)&meson_rng_priv, + }, + { + .compatible = "amlogic,meson-s4-rng", + .data = (ulong)&meson_rng_priv_s4, }, {}, }; -- 2.25.1
[PATCH v1] drivers: don't compile Secure Monitor UCLASS unconditionally
It makes no sense to compile Secure Monitor unconditionally. For example, this break the SPL build on boards with a small allowed SPL image size. Fixes: 126fbbefd89e ("drivers: introduce Secure Monitor uclass") Signed-off-by: Alexey Romanov --- drivers/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/Makefile b/drivers/Makefile index b7bd3633b1..1a768fed2b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/ obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/ obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ obj-$(CONFIG_$(SPL_)SYSINFO) += sysinfo/ +obj-$(CONFIG_$(SPL_TPL_)SM) += sm/ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ obj-$(CONFIG_XEN) += xen/ obj-$(CONFIG_$(SPL_)FPGA) += fpga/ @@ -124,4 +125,3 @@ obj-$(CONFIG_DM_RNG) += rng/ endif obj-y += soc/ -obj-y += sm/ -- 2.25.1
[PATCH v1] rng: add dm_rng_read_default() helper
Add dm_rng_read_default() function, which obtain a series of random bytes. In some cases, such function would be useful because it allows the caller to abstract away from RNG device. Signed-off-by: Alexey Romanov --- drivers/rng/rng-uclass.c | 20 include/rng.h| 10 ++ 2 files changed, 30 insertions(+) diff --git a/drivers/rng/rng-uclass.c b/drivers/rng/rng-uclass.c index 53108e1b31..3a8fb7d276 100644 --- a/drivers/rng/rng-uclass.c +++ b/drivers/rng/rng-uclass.c @@ -19,6 +19,26 @@ int dm_rng_read(struct udevice *dev, void *buffer, size_t size) return ops->read(dev, buffer, size); } +int dm_rng_read_default(void *buffer, size_t size) +{ + struct udevice *rng; + int ret; + + ret = uclass_get_device(UCLASS_RNG, 0, &rng); + if (ret) { + pr_err("Can't get RNG device (%d)\n", ret); + return ret; + } + + ret = dm_rng_read(rng, buffer, size); + if (ret) { + pr_err("Can't read from RNG device (%d)\n", ret); + return ret; + } + + return 0; +} + UCLASS_DRIVER(rng) = { .name = "rng", .id = UCLASS_RNG, diff --git a/include/rng.h b/include/rng.h index 37af554363..5537daae88 100644 --- a/include/rng.h +++ b/include/rng.h @@ -20,6 +20,16 @@ struct udevice; */ int dm_rng_read(struct udevice *dev, void *buffer, size_t size); +/** + * dm_rng_read_default() - same as dm_rng_read(), except that caller + * don't need to pass an argument with RNG udevice. + * @buffer:input buffer to put the read random seed into + * @size: number of bytes of random seed read + * + * Return: 0 if OK, -ve on error + */ +int dm_rng_read_default(void *buffer, size_t size); + /** * struct dm_rng_ops - operations for the hwrng uclass * -- 2.25.1
[PATCH v1 0/2] Meson A1: fix USB and NAND stack
Hello! After a recent sync device tree with the Linux Kernel, some drivers broke. These patchset will fix that. Alexey Romanov (1): clk: a1: add new clocks for USB stack Dmitry Rokosov (1): drivers: sm: bind child sm devices in the device tree drivers/clk/meson/a1.c | 6 ++ drivers/sm/meson-sm.c | 1 + 2 files changed, 7 insertions(+) -- 2.25.1
[PATCH v1 1/2] clk: a1: add new clocks for USB stack
Since we sync device tree with Linux, we have to add this clock definition for USB stack. Signed-off-by: Alexey Romanov --- drivers/clk/meson/a1.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c index 1075ba7333..d0f5bb3753 100644 --- a/drivers/clk/meson/a1.c +++ b/drivers/clk/meson/a1.c @@ -241,6 +241,12 @@ static const struct meson_clk_info *meson_clocks[] = { [CLKID_USB_PHY_IN] = CLK_GATE("usb_phy_in", A1_SYS_OSCIN_CTRL, 2, EXTERNAL_XTAL ), + [CLKID_USB_CTRL_IN] = CLK_GATE("usb_ctrl_in", A1_SYS_OSCIN_CTRL, 3, + EXTERNAL_XTAL + ), + [CLKID_USB_CTRL] = CLK_GATE("usb_ctrl", A1_SYS_CLK_EN0, 28, + CLKID_SYS + ), [CLKID_USB_PHY] = CLK_GATE("usb_phy", A1_SYS_CLK_EN0, 27, CLKID_SYS ), -- 2.25.1
[PATCH v1 2/2] drivers: sm: bind child sm devices in the device tree
From: Dmitry Rokosov One well-known sm child device that provides secure power control is the Secure Power Controller. This device utilizes SMC calls to communicate with power domains on the secure monitor side. Signed-off-by: Dmitry Rokosov Signed-off-by: Alexey Romanov --- drivers/sm/meson-sm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/sm/meson-sm.c b/drivers/sm/meson-sm.c index faef369f35..1dd1584855 100644 --- a/drivers/sm/meson-sm.c +++ b/drivers/sm/meson-sm.c @@ -194,6 +194,7 @@ U_BOOT_DRIVER(meson_sm) = { .id = UCLASS_SM, .of_match = meson_sm_ids, .probe = meson_sm_probe, + .bind = dm_scan_fdt_dev, .priv_auto = sizeof(struct meson_sm_priv), .ops = &sm_ops, }; -- 2.25.1
[PATCH v2 0/2] Add dm_rng_read_default() helper
Hello! This patchset adds dm_rng_read_default() helper function, that selects the first rng device and uses it to obtain random bytes. V2: - Move platform_get_rng_device() to rng-uclass.c. - Re-implement it to get first successfully probed device. - Use it in dm_rng_read_default(). Alexey Romanov (2): rng: move platform_get_rng_device() to rng-uclass.c rng: add dm_rng_read_default() helper drivers/rng/rng-uclass.c | 34 ++ include/efi_rng.h| 2 -- include/rng.h| 21 + lib/efi_loader/efi_rng.c | 27 --- 4 files changed, 55 insertions(+), 29 deletions(-) -- 2.30.1
[PATCH v2 2/2] rng: add dm_rng_read_default() helper
Add dm_rng_read_default() function, which obtain a series of random bytes. In some cases, such function would be useful because it allows the caller to abstract away from RNG device. Signed-off-by: Alexey Romanov --- drivers/rng/rng-uclass.c | 18 ++ include/rng.h| 10 ++ 2 files changed, 28 insertions(+) diff --git a/drivers/rng/rng-uclass.c b/drivers/rng/rng-uclass.c index d7236b9335..e298623e1d 100644 --- a/drivers/rng/rng-uclass.c +++ b/drivers/rng/rng-uclass.c @@ -35,6 +35,24 @@ int dm_rng_read(struct udevice *dev, void *buffer, size_t size) return ops->read(dev, buffer, size); } +int dm_rng_read_default(void *buffer, size_t size) +{ + struct udevice *rng; + int ret; + + ret = platform_get_rng_device(&rng); + if (ret) + return ret; + + ret = dm_rng_read(rng, buffer, size); + if (ret) { + pr_err("Can't read from RNG device (%d)\n", ret); + return ret; + } + + return 0; +} + UCLASS_DRIVER(rng) = { .name = "rng", .id = UCLASS_RNG, diff --git a/include/rng.h b/include/rng.h index 255c85d3e8..6412fedad2 100644 --- a/include/rng.h +++ b/include/rng.h @@ -20,6 +20,16 @@ struct udevice; */ int dm_rng_read(struct udevice *dev, void *buffer, size_t size); +/** + * dm_rng_read_default() - same as dm_rng_read(), except that caller + * don't need to pass an argument with RNG udevice. + * @buffer:input buffer to put the read random seed into + * @size: number of bytes of random seed read + * + * Return: 0 if OK, -ve on error + */ +int dm_rng_read_default(void *buffer, size_t size); + /** * platform_get_rng_device() - retrieve random number generator * -- 2.30.1
[PATCH v2 1/2] rng: move platform_get_rng_device() to rng-uclass.c
The correct declaration place for platform_get_rng_device() function is here. Also, this function is re-implemented to provide the first successfully probed RNG device. Signed-off-by: Alexey Romanov --- drivers/rng/rng-uclass.c | 16 include/efi_rng.h| 2 -- include/rng.h| 11 +++ lib/efi_loader/efi_rng.c | 27 --- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/drivers/rng/rng-uclass.c b/drivers/rng/rng-uclass.c index 53108e1b31..d7236b9335 100644 --- a/drivers/rng/rng-uclass.c +++ b/drivers/rng/rng-uclass.c @@ -9,6 +9,22 @@ #include #include +int platform_get_rng_device(struct udevice **dev) +{ + int ret; + struct udevice *devp; + + ret = uclass_first_device_check(UCLASS_RNG, &devp); + if (ret) { + pr_err("Unable to get RNG device (%d)\n", ret); + return -ENODEV; + } + + *dev = devp; + + return 0; +} + int dm_rng_read(struct udevice *dev, void *buffer, size_t size) { const struct dm_rng_ops *ops = device_get_ops(dev); diff --git a/include/efi_rng.h b/include/efi_rng.h index 3c622381cb..f22e54adb0 100644 --- a/include/efi_rng.h +++ b/include/efi_rng.h @@ -23,6 +23,4 @@ struct efi_rng_protocol { efi_uintn_t rng_value_length, uint8_t *rng_value); }; -efi_status_t platform_get_rng_device(struct udevice **dev); - #endif /* _EFI_RNG_H_ */ diff --git a/include/rng.h b/include/rng.h index 37af554363..255c85d3e8 100644 --- a/include/rng.h +++ b/include/rng.h @@ -20,6 +20,17 @@ struct udevice; */ int dm_rng_read(struct udevice *dev, void *buffer, size_t size); +/** + * platform_get_rng_device() - retrieve random number generator + * + * This function retrieves the first udevice implementing a hardware + * random number generator. Device is already probed. + * + * @dev: udevice + * Return: status code + */ +int platform_get_rng_device(struct udevice **dev); + /** * struct dm_rng_ops - operations for the hwrng uclass * diff --git a/lib/efi_loader/efi_rng.c b/lib/efi_loader/efi_rng.c index bb11d8d0e0..0d8bf770f5 100644 --- a/lib/efi_loader/efi_rng.c +++ b/lib/efi_loader/efi_rng.c @@ -17,33 +17,6 @@ DECLARE_GLOBAL_DATA_PTR; const efi_guid_t efi_guid_rng_protocol = EFI_RNG_PROTOCOL_GUID; -/** - * platform_get_rng_device() - retrieve random number generator - * - * This function retrieves the udevice implementing a hardware random - * number generator. - * - * This function may be overridden if special initialization is needed. - * - * @dev: udevice - * Return: status code - */ -__weak efi_status_t platform_get_rng_device(struct udevice **dev) -{ - int ret; - struct udevice *devp; - - ret = uclass_get_device(UCLASS_RNG, 0, &devp); - if (ret) { - debug("Unable to get rng device\n"); - return EFI_DEVICE_ERROR; - } - - *dev = devp; - - return EFI_SUCCESS; -} - /** * rng_getinfo() - get information about random number generation * -- 2.30.1
Re: [PATCH v1 1/2] drivers: firmware: introduce Meson Secure Monitor driver
Hi, On Tue, Aug 22, 2023 at 10:24:23AM +0200, neil.armstr...@linaro.org wrote: > On 21/08/2023 21:11, Simon Glass wrote: > > Hi Neil, > > > > On Mon, 21 Aug 2023 at 03:16, neil.armstr...@linaro.org > > wrote: > > > > > > Hi, > > > > > > On 16/07/2023 01:40, Simon Glass wrote: > > > > Hi, > > > > > > > > On Thu, 13 Jul 2023 at 23:30, AKASHI Takahiro > > > > wrote: > > > > > > > > > > On Tue, Jul 11, 2023 at 01:13:29PM -0600, Simon Glass wrote: > > > > > > +AKASHI Takahiro > > > > > > > > > > Me? > > > > > > > > Yes, I'm asking for your help to try to clean this stuff up. > > > > > > The thread is long and hard to answer directly, but as AKASHI > > > said there's no point to add a SMC class since it's only the message > > > passing instruction, and there's no point using remoteproc since the > > > firmware runs on a separate secure state of the same CPU. > > > > > > And I don't see how we can actually define a finite set of ops because > > > none of the secure firmware interfaces has even similar functions. > > > > > > So a new UCLASS for each firmware interface should be added, not sure > > > this is scalable or required since those firmwares are mainly SoC or > > > vendor specific, except the PSCI or other ARM specific interfaces of > > > course. > > > > > > So I think UCLASS_FIRMWARE is good enough since it avoids using > > > UCLASS_MISC, > > > but it should be probably documented somewhere that the ops are > > > implementation > > > defined. > > > > Yes it needs docs...but what exactly is the 'firmware' uclass? I > > assumed it was for loading firmware into a device, but it seems that > > it is something else? > > Nop, it's based on the same "firmware" naming as Linux, which is an interface > with a system control firmware like PSCI, SCPI... not to interact with > loadable > co-processors. > > Systems do have multiple interfaces implemented like PSCI, SCPI, OPTEE and > other > vendor specific ones like Alexey is changing, all via the same instruction > call. > > > > > Perhaps we should have a UCLASS_SVC (supervisor call) or something > > like that, rather than continuing with firmware? You propose to create UCLASS with an interface consisting of functions of something like: ->smc_call(), ->hvc_call()? In this case, it seems ARM specific. Or UCLASS with only one callback, different for different archs, which will call the hypervisor or something like that. In my understanding, this add-on are redundant. I still think UCLASS firmware is the best fit for my Secure Monitor implementation at the moment. > > I have no opinion on that, I don't think the call type is significant here. > > Neil > > > > > [..] > > > > Regards, > > Simon > -- Thank you, Alexey
Re: [PATCH v1 1/2] drivers: firmware: introduce Meson Secure Monitor driver
Hi Simon, On Tue, Aug 22, 2023 at 12:56:32PM -0600, Simon Glass wrote: > Hi Alexey, > > On Tue, 22 Aug 2023 at 06:59, Alexey Romanov > wrote: > > > > Hi, > > > > On Tue, Aug 22, 2023 at 10:24:23AM +0200, neil.armstr...@linaro.org wrote: > > > On 21/08/2023 21:11, Simon Glass wrote: > > > > Hi Neil, > > > > > > > > On Mon, 21 Aug 2023 at 03:16, neil.armstr...@linaro.org > > > > wrote: > > > > > > > > > > Hi, > > > > > > > > > > On 16/07/2023 01:40, Simon Glass wrote: > > > > > > Hi, > > > > > > > > > > > > On Thu, 13 Jul 2023 at 23:30, AKASHI Takahiro > > > > > > wrote: > > > > > > > > > > > > > > On Tue, Jul 11, 2023 at 01:13:29PM -0600, Simon Glass wrote: > > > > > > > > +AKASHI Takahiro > > > > > > > > > > > > > > Me? > > > > > > > > > > > > Yes, I'm asking for your help to try to clean this stuff up. > > > > > > > > > > The thread is long and hard to answer directly, but as AKASHI > > > > > said there's no point to add a SMC class since it's only the message > > > > > passing instruction, and there's no point using remoteproc since the > > > > > firmware runs on a separate secure state of the same CPU. > > > > > > > > > > And I don't see how we can actually define a finite set of ops because > > > > > none of the secure firmware interfaces has even similar functions. > > > > > > > > > > So a new UCLASS for each firmware interface should be added, not sure > > > > > this is scalable or required since those firmwares are mainly SoC or > > > > > vendor specific, except the PSCI or other ARM specific interfaces of > > > > > course. > > > > > > > > > > So I think UCLASS_FIRMWARE is good enough since it avoids using > > > > > UCLASS_MISC, > > > > > but it should be probably documented somewhere that the ops are > > > > > implementation > > > > > defined. > > > > > > > > Yes it needs docs...but what exactly is the 'firmware' uclass? I > > > > assumed it was for loading firmware into a device, but it seems that > > > > it is something else? > > > > > > Nop, it's based on the same "firmware" naming as Linux, which is an > > > interface > > > with a system control firmware like PSCI, SCPI... not to interact with > > > loadable > > > co-processors. > > > > > > Systems do have multiple interfaces implemented like PSCI, SCPI, OPTEE > > > and other > > > vendor specific ones like Alexey is changing, all via the same > > > instruction call. > > > > > > > > > > > Perhaps we should have a UCLASS_SVC (supervisor call) or something > > > > like that, rather than continuing with firmware? > > > > You propose to create UCLASS with an interface consisting of functions > > of something like: ->smc_call(), ->hvc_call()? In this case, it seems > > ARM specific. > > Yes, but we have a lot of arch-specific interfaces. > > > > > Or UCLASS with only one callback, different for different archs, which > > will call the hypervisor or something like that. In my understanding, > > this add-on are redundant. > > OK. > > > > > I still think UCLASS firmware is the best fit for my Secure Monitor > > implementation at the moment. > > How about you create a UCLASS_MESON_SM then? > > I don't really like the idea of a uclass with no standard API. One > goal is to help people understand things and can't see that helping. OK. Will do it in v2. > > > > > > > > > I have no opinion on that, I don't think the call type is significant > > > here. > > > > > > Neil > > > > > > > > > > > [..] > > > > > > > > Regards, > > > > Simon > > > > > > > -- > > Thank you, > > Alexey > > Regards, > Simon -- Thank you, Alexey
[PATCH v2 0/8] Add SM uclass and Meson SM driver
Hello! At the moment, there is no single general approach to using secure monitor in U-Boot, there is only the smc_call() function, over which everyone builds their own add-ons. This patchset is designed to solve this problem by adding a new uclass - SM_UCLASS. This UCLASS export following generic API: 1. sm_call() - generic SMC call to the secure-monitor 2. sm_call_read() - retrieve data from secure-monitor 3. sm_call_write() - send data to secure-monitor In the future, it is necessary to completely get rid of raw smc_call() calls, replacing them with the use of SM_UCLASS based drivers. V2: - Add SM UCLASS - Add SM sandbox driver - Add test for sandbox driver - Meson Secure Monitor driver now based on SM_UCLASS - Fix include order in arch/arm/mach-meson/sm.c Also, during the discussion in V1 of this patchset, it was discussed to create MESON_SM_UCLASS, but I considered such a uclass to be too arch-specific. That's why I suggest SM_UCLASS, which is not so arch-specific: secure monitor can used for whole ARM devices, not only for Amlogic SoC's. Alexey Romanov (8): drivers: introduce Secure Monitor uclass sandbox: add sandobx sm uclass driver sandbox: dts: add meson secure monitor node sandbox: add tests for UCLASS_SM sandbox: defconfig: enable CONFIG_SM option drivers: introduce Meson Secure Monitor driver arch: meson: sm: set correct order of the includes arch: meson: use secure monitor driver MAINTAINERS | 1 + arch/arm/mach-meson/Kconfig | 1 + arch/arm/mach-meson/sm.c| 116 +++-- arch/sandbox/dts/test.dts | 4 + configs/sandbox_defconfig | 1 + drivers/Kconfig | 2 + drivers/Makefile| 1 + drivers/sm/Kconfig | 9 ++ drivers/sm/Makefile | 5 + drivers/sm/meson-sm.c | 198 drivers/sm/sandbox-sm.c | 76 ++ drivers/sm/sm-uclass.c | 55 ++ include/dm/uclass-id.h | 1 + include/meson/sm.h | 19 include/sandbox-sm.h| 18 include/sm-uclass.h | 72 + include/sm.h| 67 test/dm/Makefile| 1 + test/dm/sm.c| 65 19 files changed, 656 insertions(+), 56 deletions(-) create mode 100644 drivers/sm/Kconfig create mode 100644 drivers/sm/Makefile create mode 100644 drivers/sm/meson-sm.c create mode 100644 drivers/sm/sandbox-sm.c create mode 100644 drivers/sm/sm-uclass.c create mode 100644 include/meson/sm.h create mode 100644 include/sandbox-sm.h create mode 100644 include/sm-uclass.h create mode 100644 include/sm.h create mode 100644 test/dm/sm.c -- 2.25.1
[PATCH v2 1/8] drivers: introduce Secure Monitor uclass
At the moment, we don't have a common API for working with SM, only the smc_call() function. This approach is not generic and difficult to configure and maintain. This patch adds UCLASS_SM with the generic API: - sm_call() - sm_call_write() - sm_call_read() These functions operate with struct pt_regs, which describes Secure Monitor arguments. Signed-off-by: Alexey Romanov --- drivers/Kconfig| 2 ++ drivers/Makefile | 1 + drivers/sm/Kconfig | 2 ++ drivers/sm/Makefile| 3 ++ drivers/sm/sm-uclass.c | 55 include/dm/uclass-id.h | 1 + include/sm-uclass.h| 72 ++ include/sm.h | 67 +++ 8 files changed, 203 insertions(+) create mode 100644 drivers/sm/Kconfig create mode 100644 drivers/sm/Makefile create mode 100644 drivers/sm/sm-uclass.c create mode 100644 include/sm-uclass.h create mode 100644 include/sm.h diff --git a/drivers/Kconfig b/drivers/Kconfig index 75ac149d31..72e6405322 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -112,6 +112,8 @@ source "drivers/scsi/Kconfig" source "drivers/serial/Kconfig" +source "drivers/sm/Kconfig" + source "drivers/smem/Kconfig" source "drivers/sound/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 6f1de58e00..b7bd3633b1 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -124,3 +124,4 @@ obj-$(CONFIG_DM_RNG) += rng/ endif obj-y += soc/ +obj-y += sm/ diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig new file mode 100644 index 00..6cc6d55578 --- /dev/null +++ b/drivers/sm/Kconfig @@ -0,0 +1,2 @@ +config SM + bool "Enable Secure Monitor driver support" diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile new file mode 100644 index 00..9f4683ba06 --- /dev/null +++ b/drivers/sm/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += sm-uclass.o diff --git a/drivers/sm/sm-uclass.c b/drivers/sm/sm-uclass.c new file mode 100644 index 00..78af857026 --- /dev/null +++ b/drivers/sm/sm-uclass.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include + +static const struct sm_ops *get_sm_ops(struct udevice *dev) +{ + return (const struct sm_ops *)dev->driver->ops; +} + +int sm_call(struct udevice *dev, u32 cmd, s32 *ret, struct pt_regs *args) +{ + const struct sm_ops *ops = get_sm_ops(dev); + + if (ops->sm_call) + return ops->sm_call(dev, cmd, ret, args); + + return -EPROTONOSUPPORT; +} + +int sm_call_read(struct udevice *dev, void *buffer, size_t size, +u32 cmd, struct pt_regs *args) +{ + const struct sm_ops *ops = get_sm_ops(dev); + + if (ops->sm_call_read) + return ops->sm_call_read(dev, buffer, size, cmd, +args); + + return -EPROTONOSUPPORT; +} + +int sm_call_write(struct udevice *dev, void *buffer, size_t size, + u32 cmd, struct pt_regs *args) +{ + const struct sm_ops *ops = get_sm_ops(dev); + + if (ops->sm_call_write) + return ops->sm_call_write(dev, buffer, size, cmd, + args); + + return -EPROTONOSUPPORT; +} + +UCLASS_DRIVER(sm) = { + .name = "sm", + .id = UCLASS_SM, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 376f741cc2..545c9352a8 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -80,6 +80,7 @@ enum uclass_id { UCLASS_MDIO,/* MDIO bus */ UCLASS_MDIO_MUX,/* MDIO MUX/switch */ UCLASS_MEMORY, /* Memory Controller device */ + UCLASS_SM, /* Secure Monitor driver */ UCLASS_MISC,/* Miscellaneous device */ UCLASS_MMC, /* SD / MMC card or chip */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ diff --git a/include/sm-uclass.h b/include/sm-uclass.h new file mode 100644 index 00..c114484044 --- /dev/null +++ b/include/sm-uclass.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#ifndef __SM_UCLASS_H__ +#define __SM_UCLASS_H__ + +#include +#include + +struct udevice; + +/** + * struct sm_ops - The functions that a SM driver must implement. + * + * @sm_call: Request a secure monitor call with specified command. + * + * @sm_call_read: Request a secure monitor call and retrieve data + * from secure-monitor (depends on specified command). + * + * @sm_call_write: Request a secure monitor call and send data + * to secure-monitor (depends on specified command). + * + * The individual methods are described more
[PATCH v2 2/8] sandbox: add sandobx sm uclass driver
This patch adds sandbox secure monitor driver. Signed-off-by: Alexey Romanov --- drivers/sm/Makefile | 1 + drivers/sm/sandbox-sm.c | 76 + include/sandbox-sm.h| 18 ++ 3 files changed, 95 insertions(+) create mode 100644 drivers/sm/sandbox-sm.c create mode 100644 include/sandbox-sm.h diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile index 9f4683ba06..af5f475c2b 100644 --- a/drivers/sm/Makefile +++ b/drivers/sm/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += sm-uclass.o +obj-$(CONFIG_SANDBOX) += sandbox-sm.o diff --git a/drivers/sm/sandbox-sm.c b/drivers/sm/sandbox-sm.c new file mode 100644 index 00..109ddb2af5 --- /dev/null +++ b/drivers/sm/sandbox-sm.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include +#include +#include + +static u8 test_buffer[SZ_4K]; + +static int sandbox_sm_call(struct udevice *dev, u32 cmd_index, s32 *smc_ret, + struct pt_regs *args) +{ + if (cmd_index >= SANDBOX_SMC_CMD_COUNT) + return -EINVAL; + + if (smc_ret) + *smc_ret = 0; + + return 0; +} + +static int sandbox_sm_call_read(struct udevice *dev, void *buffer, size_t size, + u32 cmd_index, struct pt_regs *args) +{ + if (cmd_index >= SANDBOX_SMC_CMD_COUNT || !buffer) + return -EINVAL; + + if (size > sizeof(test_buffer)) + return -EINVAL; + + memcpy(buffer, test_buffer, size); + + return size; +} + +static int sandbox_sm_call_write(struct udevice *dev, void *buffer, size_t size, +u32 cmd_index, struct pt_regs *args) +{ + if (cmd_index >= SANDBOX_SMC_CMD_COUNT || !buffer) + return -EINVAL; + + if (size > sizeof(test_buffer)) + return -EINVAL; + + memcpy(test_buffer, buffer, size); + + return size; +} + +static const struct udevice_id sandbox_sm_ids[] = { + { + .compatible = "sandbox,sm", + }, + {}, +}; + +static const struct sm_ops sandbox_sm_ops = { + .sm_call = sandbox_sm_call, + .sm_call_read = sandbox_sm_call_read, + .sm_call_write = sandbox_sm_call_write, +}; + +U_BOOT_DRIVER(sm) = { + .name = "sm", + .id = UCLASS_SM, + .of_match = sandbox_sm_ids, + .ops = &sandbox_sm_ops, +}; diff --git a/include/sandbox-sm.h b/include/sandbox-sm.h new file mode 100644 index 00..91c30d501d --- /dev/null +++ b/include/sandbox-sm.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#ifndef __SANDBOX_SM_H__ +#define __SANDBOX_SM_H__ + +enum sandbox_smc_cmd { + SANDBOX_SMC_CMD_READ_MEM, + SANDBOX_SMC_CMD_WRITE_MEM, + SANDBOX_SMC_CMD_COMMON, + SANDBOX_SMC_CMD_COUNT, +}; + +#endif -- 2.25.1
[PATCH v2 3/8] sandbox: dts: add meson secure monitor node
We need this to test UCLASS_SM. Signed-off-by: Alexey Romanov --- arch/sandbox/dts/test.dts | 4 1 file changed, 4 insertions(+) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index dffe10adbf..4475aa58a6 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -693,6 +693,10 @@ }; }; }; + + sm: secure-monitor { + compatible = "sandbox,sm"; + }; }; fpga { -- 2.25.1
[PATCH v2 4/8] sandbox: add tests for UCLASS_SM
This patchs adds simple tests for Secure Monitor uclass. Signed-off-by: Alexey Romanov --- test/dm/Makefile | 1 + test/dm/sm.c | 65 2 files changed, 66 insertions(+) create mode 100644 test/dm/sm.c diff --git a/test/dm/Makefile b/test/dm/Makefile index 7a79b6e1a2..30550a62ad 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_DM_SPI) += spi.o obj-$(CONFIG_SPMI) += spmi.o obj-y += syscon.o obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o +obj-$(CONFIG_SM) += sm.o obj-$(CONFIG_SYSINFO) += sysinfo.o obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o obj-$(CONFIG_UT_DM) += tag.o diff --git a/test/dm/sm.c b/test/dm/sm.c new file mode 100644 index 00..7ebb0c9c85 --- /dev/null +++ b/test/dm/sm.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int dm_test_sm(struct unit_test_state *uts) +{ + struct udevice *dev; + struct pt_regs regs; + char buffer[128] = { 0 }; + char test_string[] = "secure-monitor"; + int ret, val; + + ut_assertok(uclass_get_device_by_name(UCLASS_SM, + "secure-monitor", &dev)); + + ret = sm_call(dev, SANDBOX_SMC_CMD_COUNT, NULL, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call(dev, SANDBOX_SMC_CMD_COMMON, &val, ®s); + ut_asserteq(ret, 0); + ut_asserteq(val, 0); + + ret = sm_call_write(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_COUNT, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, SZ_4K + 1, + SANDBOX_SMC_CMD_WRITE_MEM, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_COUNT, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, SZ_4K + 1, + SANDBOX_SMC_CMD_READ_MEM, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, test_string, sizeof(test_string), + SANDBOX_SMC_CMD_WRITE_MEM, ®s); + ut_asserteq(ret, sizeof(test_string)); + + ret = sm_call_read(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_READ_MEM, ®s); + ut_asserteq(ret, sizeof(buffer)); + + ut_asserteq_str(buffer, test_string); + + return 0; +} + +DM_TEST(dm_test_sm, UT_TESTF_SCAN_FDT); -- 2.25.1
[PATCH v2 5/8] sandbox: defconfig: enable CONFIG_SM option
We use this option for test UCLASS_SM. Signed-off-by: Alexey Romanov --- configs/sandbox_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index be46cae7aa..0745a4ecca 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -270,6 +270,7 @@ CONFIG_RTC_RV8803=y CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_SANDBOX_SERIAL=y +CONFIG_SM=y CONFIG_SMEM=y CONFIG_SANDBOX_SMEM=y CONFIG_SOUND=y -- 2.25.1
[PATCH v2 7/8] arch: meson: sm: set correct order of the includes
The common.h header should always be first, followed by other headers in order, then headers with directories, then local files. Signed-off-by: Alexey Romanov --- arch/arm/mach-meson/sm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index d600c64d0b..b5dd6c6d39 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -6,7 +6,10 @@ */ #include +#include #include +#include +#include #include #include #include @@ -14,10 +17,7 @@ #include #include #include -#include #include -#include -#include #define FN_GET_SHARE_MEM_INPUT_BASE0x8220 #define FN_GET_SHARE_MEM_OUTPUT_BASE 0x8221 -- 2.25.1
[PATCH v2 6/8] drivers: introduce Meson Secure Monitor driver
This patch adds an implementation of the Meson Secure Monitor driver based on UCLASS_SM. Signed-off-by: Alexey Romanov --- MAINTAINERS | 1 + drivers/sm/Kconfig| 7 ++ drivers/sm/Makefile | 1 + drivers/sm/meson-sm.c | 198 ++ include/meson/sm.h| 19 5 files changed, 226 insertions(+) create mode 100644 drivers/sm/meson-sm.c create mode 100644 include/meson/sm.h diff --git a/MAINTAINERS b/MAINTAINERS index 6c64427782..bdc364fd4c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -158,6 +158,7 @@ F: drivers/net/phy/meson-gxl.c F: drivers/adc/meson-saradc.c F: drivers/phy/meson* F: drivers/mmc/meson_gx_mmc.c +F: drivers/sm/meson-sm.c F: drivers/spi/meson_spifc.c F: drivers/pinctrl/meson/ F: drivers/power/domain/meson-gx-pwrc-vpu.c diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig index 6cc6d55578..b4cc3f768e 100644 --- a/drivers/sm/Kconfig +++ b/drivers/sm/Kconfig @@ -1,2 +1,9 @@ config SM bool "Enable Secure Monitor driver support" + +config MESON_SM + bool "Amlogic Secure Monitor driver" + depends on SM + default n + help + Say y here to enable the Amlogic secure monitor driver. diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile index af5f475c2b..da81ee898a 100644 --- a/drivers/sm/Makefile +++ b/drivers/sm/Makefile @@ -2,3 +2,4 @@ obj-y += sm-uclass.o obj-$(CONFIG_SANDBOX) += sandbox-sm.o +obj-$(CONFIG_MESON_SM) += meson-sm.o diff --git a/drivers/sm/meson-sm.c b/drivers/sm/meson-sm.c new file mode 100644 index 00..25adaf4560 --- /dev/null +++ b/drivers/sm/meson-sm.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct meson_sm_cmd { + u32 smc_id; +}; + +#define SET_CMD(index, id) \ + [index] = { \ + .smc_id = (id), \ + } + +struct meson_sm_data { + u32 cmd_get_shmem_in; + u32 cmd_get_shmem_out; + unsigned int shmem_size; + struct meson_sm_cmd cmd[]; +}; + +struct meson_sm_priv { + void *sm_shmem_in; + void *sm_shmem_out; + const struct meson_sm_data *data; +}; + +static unsigned long __meson_sm_call(u32 cmd, const struct pt_regs *args) +{ + struct pt_regs r = *args; + + r.regs[0] = cmd; + smc_call(&r); + + return r.regs[0]; +}; + +static u32 meson_sm_get_cmd(const struct meson_sm_data *data, + u32 cmd_index) +{ + struct meson_sm_cmd cmd; + + if (cmd_index >= MESON_SMC_CMD_COUNT) + return 0; + + cmd = data->cmd[cmd_index]; + return cmd.smc_id; +} + +static int meson_sm_call(struct udevice *dev, u32 cmd_index, s32 *retval, +struct pt_regs *args) +{ + struct meson_sm_priv *priv = dev_get_priv(dev); + u32 cmd, ret; + + cmd = meson_sm_get_cmd(priv->data, cmd_index); + if (!cmd) + return -ENOENT; + + ret = __meson_sm_call(cmd, args); + if (retval) + *retval = ret; + + return 0; +} + +static int meson_sm_call_read(struct udevice *dev, void *buffer, size_t size, + u32 cmd_index, struct pt_regs *args) +{ + struct meson_sm_priv *priv = dev_get_priv(dev); + s32 nbytes; + int ret; + + if (!buffer || size > priv->data->shmem_size) + return -EINVAL; + + ret = meson_sm_call(dev, cmd_index, &nbytes, args); + if (ret) + return ret; + + if (nbytes < 0 || nbytes > size) + return -ENOBUFS; + + /* In some cases (for example GET_CHIP_ID command), +* SMC doesn't return the number of bytes read, even +* though the bytes were actually read into sm_shmem_out. +* So this check is needed. +*/ + ret = nbytes; + if (!nbytes) + nbytes = size; + + memcpy(buffer, priv->sm_shmem_out, nbytes); + + return ret; +} + +static int meson_sm_call_write(struct udevice *dev, void *buffer, size_t size, + u32 cmd_index, struct pt_regs *args) +{ + struct meson_sm_priv *priv = dev_get_priv(dev); + s32 nbytes; + int ret; + + if (!buffer || size > priv->data->shmem_size) + return -EINVAL; + + memcpy(priv->sm_shmem_in, buffer, size); + + ret = meson_sm_call(dev, cmd_index, &nbytes, args); + if (ret) + return ret; + + if (nbytes <= 0 || nbytes > size) + return -EIO; + + return nbytes; +} + +static int meson_sm_probe(struct udevice *dev) +{ + struct meson_sm_priv *priv = dev_get_priv(dev);
[PATCH v2 8/8] arch: meson: use secure monitor driver
Now we have to use UCLASS_SM driver instead of raw smc_call() function call. Signed-off-by: Alexey Romanov --- arch/arm/mach-meson/Kconfig | 1 + arch/arm/mach-meson/sm.c| 110 +++- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 669ca09a00..d6c8905806 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -11,6 +11,7 @@ config MESON64_COMMON select PWRSEQ select MMC_PWRSEQ select BOARD_LATE_INIT + select MESON_SM imply CMD_DM config MESON_GX diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index b5dd6c6d39..0c60aa8695 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,70 +19,62 @@ #include #include #include +#include -#define FN_GET_SHARE_MEM_INPUT_BASE0x8220 -#define FN_GET_SHARE_MEM_OUTPUT_BASE 0x8221 -#define FN_EFUSE_READ 0x8230 -#define FN_EFUSE_WRITE 0x8231 -#define FN_CHIP_ID 0x8244 -#define FN_PWRDM_SET 0x8293 - -static void *shmem_input; -static void *shmem_output; - -static void meson_init_shmem(void) +static inline struct udevice *meson_get_sm_device(void) { - struct pt_regs regs; - - if (shmem_input && shmem_output) - return; + struct udevice *dev; + int err; - regs.regs[0] = FN_GET_SHARE_MEM_INPUT_BASE; - smc_call(®s); - shmem_input = (void *)regs.regs[0]; - - regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE; - smc_call(®s); - shmem_output = (void *)regs.regs[0]; + err = uclass_get_device_by_name(UCLASS_SM, "secure-monitor", &dev); + if (err) { + pr_err("Mesom SM device not found\n"); + return ERR_PTR(err); + } - debug("Secure Monitor shmem: 0x%p 0x%p\n", shmem_input, shmem_output); + return dev; } ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size) { - struct pt_regs regs; + struct udevice *dev; + struct pt_regs regs = { 0 }; + int err; - meson_init_shmem(); + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); - regs.regs[0] = FN_EFUSE_READ; regs.regs[1] = offset; regs.regs[2] = size; - smc_call(®s); + err = sm_call_read(dev, buffer, size, + MESON_SMC_CMD_EFUSE_READ, ®s); + if (err < 0) + pr_err("Failed to read efuse memory (%d)\n", err); - if (regs.regs[0] == 0) - return -1; - - memcpy(buffer, shmem_output, min(size, regs.regs[0])); - - return regs.regs[0]; + return err; } ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size) { - struct pt_regs regs; - - meson_init_shmem(); + struct udevice *dev; + struct pt_regs regs = { 0 }; + int err; -memcpy(shmem_input, buffer, size); + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); - regs.regs[0] = FN_EFUSE_WRITE; regs.regs[1] = offset; regs.regs[2] = size; - smc_call(®s); + err = sm_call_write(dev, buffer, size, + MESON_SMC_CMD_EFUSE_WRITE, ®s); + if (err < 0) + pr_err("Failed to write efuse memory (%d)\n", err); - return regs.regs[0]; + return err; } #define SM_CHIP_ID_LENGTH 119 @@ -90,18 +83,21 @@ ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size) int meson_sm_get_serial(void *buffer, size_t size) { - struct pt_regs regs; + struct udevice *dev; + struct pt_regs regs = { 0 }; + u8 id_buffer[SM_CHIP_ID_LENGTH]; + int err; - meson_init_shmem(); + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); - regs.regs[0] = FN_CHIP_ID; - regs.regs[1] = 0; - regs.regs[2] = 0; + err = sm_call_read(dev, id_buffer, SM_CHIP_ID_LENGTH, + MESON_SMC_CMD_CHIP_ID_GET, ®s); + if (err < 0) + pr_err("Failed to read serial number (%d)\n", err); - smc_call(®s); - - memcpy(buffer, shmem_output + SM_CHIP_ID_OFFSET, - min_t(size_t, size, SM_CHIP_ID_SIZE)); + memcpy(buffer, id_buffer + SM_CHIP_ID_OFFSET, size); return 0; } @@ -141,13 +137,21 @@ int meson_sm_get_reboot_reason(void) int meson_sm_pwrdm_set(size_t index, int cmd) { - struct pt_regs regs; + struct udevice *dev; + struct pt_regs regs = { 0 }; + int err; + + dev = meson_get_sm_device(); +
Re: [PATCH v1 1/2] meson-a1: dts: add hw rng node
Hi Neil, On Thu, Jun 22, 2023 at 06:19:33PM +0200, neil.armstr...@linaro.org wrote: > On 21/06/2023 15:29, Alexey Romanov wrote: > > Add support for hardware random number generator > > of Amlogic Meson SoCs. > > > > Signed-off-by: Alexey Romanov > > --- > > arch/arm/dts/meson-a1.dtsi | 5 + > > 1 file changed, 5 insertions(+) > > > > diff --git a/arch/arm/dts/meson-a1.dtsi b/arch/arm/dts/meson-a1.dtsi > > index f3560cbc3a4..1f57c137384 100644 > > --- a/arch/arm/dts/meson-a1.dtsi > > +++ b/arch/arm/dts/meson-a1.dtsi > > @@ -140,6 +140,11 @@ > > clock-names = "xtal", "pclk", "baud"; > > status = "disabled"; > > }; > > + > > + hwrng: rng@5118 { > > + compatible = "amlogic,meson-rng"; > > + reg = <0x0 0x5118 0x0 0x4>; > > + }; > > }; > > gic: interrupt-controller@ff901000 { > > Weird, you introduced amlogic,meson-rng-s4 previously but you don't use it > here ? This is A1 (not S4). > > Anyway please add those to Linux first, them sync the DT to u-boot afterwards, Applied into v6.7/arm64-dt here: https://lore.kernel.org/all/20230823213630.12936-13-ddroko...@sberdevices.ru/ > > Thanks, > Neil -- Thank you, Alexey
Re: [PATCH v1 2/2] meson-a1: dts: add ao secure node
Hi Neil, On Wed, Jun 21, 2023 at 04:29:53PM +0300, Alexey Romanov wrote: > ao-secure node can be used to get information about the board, > so, for example, using show_board_info() we can get following > information for board with Meson A1 SoC: > > SoC: Amlogic Meson A1 (A113L) Revision 2c:a (1:a) > > Signed-off-by: Alexey Romanov > --- > arch/arm/dts/meson-a1.dtsi | 6 ++ > 1 file changed, 6 insertions(+) > > diff --git a/arch/arm/dts/meson-a1.dtsi b/arch/arm/dts/meson-a1.dtsi > index 1f57c137384..149cc0e23a3 100644 > --- a/arch/arm/dts/meson-a1.dtsi > +++ b/arch/arm/dts/meson-a1.dtsi > @@ -145,6 +145,12 @@ > compatible = "amlogic,meson-rng"; > reg = <0x0 0x5118 0x0 0x4>; > }; > + > + sec_AO: ao-secure@5a20 { > + compatible = "amlogic,meson-gx-ao-secure", > "syscon"; > + reg = <0x0 0x5a20 0x0 0x140>; > + amlogic,has-chip-id; > + }; > }; > > gic: interrupt-controller@ff901000 { > -- > 2.38.1 > Applied into v6.7/arm64-dt here: https://lore.kernel.org/all/20230823213630.12936-14-ddroko...@sberdevices.ru/ -- Thank you, Alexey
[PATCH v3 1/8] drivers: introduce Secure Monitor uclass
At the moment, we don't have a common API for working with SM, only the smc_call() function. This approach is not generic and difficult to configure and maintain. This patch adds UCLASS_SM with the generic API: - sm_call() - sm_call_write() - sm_call_read() These functions operate with struct pt_regs, which describes Secure Monitor arguments. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- drivers/Kconfig| 2 ++ drivers/Makefile | 1 + drivers/sm/Kconfig | 2 ++ drivers/sm/Makefile| 3 ++ drivers/sm/sm-uclass.c | 55 include/dm/uclass-id.h | 1 + include/sm-uclass.h| 72 ++ include/sm.h | 67 +++ 8 files changed, 203 insertions(+) create mode 100644 drivers/sm/Kconfig create mode 100644 drivers/sm/Makefile create mode 100644 drivers/sm/sm-uclass.c create mode 100644 include/sm-uclass.h create mode 100644 include/sm.h diff --git a/drivers/Kconfig b/drivers/Kconfig index 75ac149d31..72e6405322 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -112,6 +112,8 @@ source "drivers/scsi/Kconfig" source "drivers/serial/Kconfig" +source "drivers/sm/Kconfig" + source "drivers/smem/Kconfig" source "drivers/sound/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 6f1de58e00..b7bd3633b1 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -124,3 +124,4 @@ obj-$(CONFIG_DM_RNG) += rng/ endif obj-y += soc/ +obj-y += sm/ diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig new file mode 100644 index 00..6cc6d55578 --- /dev/null +++ b/drivers/sm/Kconfig @@ -0,0 +1,2 @@ +config SM + bool "Enable Secure Monitor driver support" diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile new file mode 100644 index 00..9f4683ba06 --- /dev/null +++ b/drivers/sm/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += sm-uclass.o diff --git a/drivers/sm/sm-uclass.c b/drivers/sm/sm-uclass.c new file mode 100644 index 00..6a8b702629 --- /dev/null +++ b/drivers/sm/sm-uclass.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include + +static const struct sm_ops *get_sm_ops(struct udevice *dev) +{ + return (const struct sm_ops *)dev->driver->ops; +} + +int sm_call(struct udevice *dev, u32 cmd, s32 *ret, struct pt_regs *args) +{ + const struct sm_ops *ops = get_sm_ops(dev); + + if (ops->sm_call) + return ops->sm_call(dev, cmd, ret, args); + + return -ENOSYS; +} + +int sm_call_read(struct udevice *dev, void *buffer, size_t size, +u32 cmd, struct pt_regs *args) +{ + const struct sm_ops *ops = get_sm_ops(dev); + + if (ops->sm_call_read) + return ops->sm_call_read(dev, buffer, size, cmd, +args); + + return -ENOSYS; +} + +int sm_call_write(struct udevice *dev, void *buffer, size_t size, + u32 cmd, struct pt_regs *args) +{ + const struct sm_ops *ops = get_sm_ops(dev); + + if (ops->sm_call_write) + return ops->sm_call_write(dev, buffer, size, cmd, + args); + + return -ENOSYS; +} + +UCLASS_DRIVER(sm) = { + .name = "sm", + .id = UCLASS_SM, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 376f741cc2..545c9352a8 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -80,6 +80,7 @@ enum uclass_id { UCLASS_MDIO,/* MDIO bus */ UCLASS_MDIO_MUX,/* MDIO MUX/switch */ UCLASS_MEMORY, /* Memory Controller device */ + UCLASS_SM, /* Secure Monitor driver */ UCLASS_MISC,/* Miscellaneous device */ UCLASS_MMC, /* SD / MMC card or chip */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ diff --git a/include/sm-uclass.h b/include/sm-uclass.h new file mode 100644 index 00..c114484044 --- /dev/null +++ b/include/sm-uclass.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#ifndef __SM_UCLASS_H__ +#define __SM_UCLASS_H__ + +#include +#include + +struct udevice; + +/** + * struct sm_ops - The functions that a SM driver must implement. + * + * @sm_call: Request a secure monitor call with specified command. + * + * @sm_call_read: Request a secure monitor call and retrieve data + * from secure-monitor (depends on specified command). + * + * @sm_call_write: Request a secure monitor call and send data + * to secure-monitor (depends on specified command). + * + * The individual methods are described more
[PATCH v3 0/8] Add SM uclass and Meson SM driver
Hello! At the moment, there is no single general approach to using secure monitor in U-Boot, there is only the smc_call() function, over which everyone builds their own add-ons. This patchset is designed to solve this problem by adding a new uclass - SM_UCLASS. This UCLASS export following generic API: 1. sm_call() - generic SMC call to the secure-monitor 2. sm_call_read() - retrieve data from secure-monitor 3. sm_call_write() - send data to secure-monitor In the future, it is necessary to completely get rid of raw smc_call() calls, replacing them with the use of SM_UCLASS based drivers. V2: - Add SM UCLASS - Add SM sandbox driver - Add test for sandbox driver - Meson Secure Monitor driver now based on SM_UCLASS - Fix include order in arch/arm/mach-meson/sm.c Also, during the discussion in V1 of this patchset, it was discussed to create MESON_SM_UCLASS, but I considered such a uclass to be too arch-specific. That's why I suggest SM_UCLASS, which is not so arch-specific: secure monitor can used for whole ARM devices, not only for Amlogic SoC's. V3: - Fix typos in commit messages - Use uclass_first_device_err() instead of uclass_get_device_by_name() - Return -ENOSYS instead of -EPROTONOSUPPORT if SM_UCLASS option not implemented Alexey Romanov (8): drivers: introduce Secure Monitor uclass sandbox: add sandbox sm uclass driver sandbox: dts: add meson secure monitor node sandbox: add tests for UCLASS_SM sandbox: defconfig: enable CONFIG_SM option drivers: introduce Meson Secure Monitor driver arch: meson: sm: set correct order of the includes arch: meson: use secure monitor driver MAINTAINERS | 1 + arch/arm/mach-meson/Kconfig | 1 + arch/arm/mach-meson/sm.c| 116 +++-- arch/sandbox/dts/test.dts | 4 + configs/sandbox_defconfig | 1 + drivers/Kconfig | 2 + drivers/Makefile| 1 + drivers/sm/Kconfig | 9 ++ drivers/sm/Makefile | 5 + drivers/sm/meson-sm.c | 198 drivers/sm/sandbox-sm.c | 76 ++ drivers/sm/sm-uclass.c | 55 ++ include/dm/uclass-id.h | 1 + include/meson/sm.h | 19 include/sandbox-sm.h| 18 include/sm-uclass.h | 72 + include/sm.h| 67 test/dm/Makefile| 1 + test/dm/sm.c| 65 19 files changed, 656 insertions(+), 56 deletions(-) create mode 100644 drivers/sm/Kconfig create mode 100644 drivers/sm/Makefile create mode 100644 drivers/sm/meson-sm.c create mode 100644 drivers/sm/sandbox-sm.c create mode 100644 drivers/sm/sm-uclass.c create mode 100644 include/meson/sm.h create mode 100644 include/sandbox-sm.h create mode 100644 include/sm-uclass.h create mode 100644 include/sm.h create mode 100644 test/dm/sm.c -- 2.25.1
[PATCH v3 2/8] sandbox: add sandbox sm uclass driver
This patch adds sandbox secure monitor driver. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- drivers/sm/Makefile | 1 + drivers/sm/sandbox-sm.c | 76 + include/sandbox-sm.h| 18 ++ 3 files changed, 95 insertions(+) create mode 100644 drivers/sm/sandbox-sm.c create mode 100644 include/sandbox-sm.h diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile index 9f4683ba06..af5f475c2b 100644 --- a/drivers/sm/Makefile +++ b/drivers/sm/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += sm-uclass.o +obj-$(CONFIG_SANDBOX) += sandbox-sm.o diff --git a/drivers/sm/sandbox-sm.c b/drivers/sm/sandbox-sm.c new file mode 100644 index 00..109ddb2af5 --- /dev/null +++ b/drivers/sm/sandbox-sm.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include +#include +#include + +static u8 test_buffer[SZ_4K]; + +static int sandbox_sm_call(struct udevice *dev, u32 cmd_index, s32 *smc_ret, + struct pt_regs *args) +{ + if (cmd_index >= SANDBOX_SMC_CMD_COUNT) + return -EINVAL; + + if (smc_ret) + *smc_ret = 0; + + return 0; +} + +static int sandbox_sm_call_read(struct udevice *dev, void *buffer, size_t size, + u32 cmd_index, struct pt_regs *args) +{ + if (cmd_index >= SANDBOX_SMC_CMD_COUNT || !buffer) + return -EINVAL; + + if (size > sizeof(test_buffer)) + return -EINVAL; + + memcpy(buffer, test_buffer, size); + + return size; +} + +static int sandbox_sm_call_write(struct udevice *dev, void *buffer, size_t size, +u32 cmd_index, struct pt_regs *args) +{ + if (cmd_index >= SANDBOX_SMC_CMD_COUNT || !buffer) + return -EINVAL; + + if (size > sizeof(test_buffer)) + return -EINVAL; + + memcpy(test_buffer, buffer, size); + + return size; +} + +static const struct udevice_id sandbox_sm_ids[] = { + { + .compatible = "sandbox,sm", + }, + {}, +}; + +static const struct sm_ops sandbox_sm_ops = { + .sm_call = sandbox_sm_call, + .sm_call_read = sandbox_sm_call_read, + .sm_call_write = sandbox_sm_call_write, +}; + +U_BOOT_DRIVER(sm) = { + .name = "sm", + .id = UCLASS_SM, + .of_match = sandbox_sm_ids, + .ops = &sandbox_sm_ops, +}; diff --git a/include/sandbox-sm.h b/include/sandbox-sm.h new file mode 100644 index 00..91c30d501d --- /dev/null +++ b/include/sandbox-sm.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#ifndef __SANDBOX_SM_H__ +#define __SANDBOX_SM_H__ + +enum sandbox_smc_cmd { + SANDBOX_SMC_CMD_READ_MEM, + SANDBOX_SMC_CMD_WRITE_MEM, + SANDBOX_SMC_CMD_COMMON, + SANDBOX_SMC_CMD_COUNT, +}; + +#endif -- 2.25.1
[PATCH v3 3/8] sandbox: dts: add meson secure monitor node
We need this to test UCLASS_SM. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- arch/sandbox/dts/test.dts | 4 1 file changed, 4 insertions(+) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index dffe10adbf..4475aa58a6 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -693,6 +693,10 @@ }; }; }; + + sm: secure-monitor { + compatible = "sandbox,sm"; + }; }; fpga { -- 2.25.1
[PATCH v3 4/8] sandbox: add tests for UCLASS_SM
This patchs adds simple tests for Secure Monitor uclass. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- test/dm/Makefile | 1 + test/dm/sm.c | 65 2 files changed, 66 insertions(+) create mode 100644 test/dm/sm.c diff --git a/test/dm/Makefile b/test/dm/Makefile index 7a79b6e1a2..30550a62ad 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_DM_SPI) += spi.o obj-$(CONFIG_SPMI) += spmi.o obj-y += syscon.o obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o +obj-$(CONFIG_SM) += sm.o obj-$(CONFIG_SYSINFO) += sysinfo.o obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o obj-$(CONFIG_UT_DM) += tag.o diff --git a/test/dm/sm.c b/test/dm/sm.c new file mode 100644 index 00..7ebb0c9c85 --- /dev/null +++ b/test/dm/sm.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int dm_test_sm(struct unit_test_state *uts) +{ + struct udevice *dev; + struct pt_regs regs; + char buffer[128] = { 0 }; + char test_string[] = "secure-monitor"; + int ret, val; + + ut_assertok(uclass_get_device_by_name(UCLASS_SM, + "secure-monitor", &dev)); + + ret = sm_call(dev, SANDBOX_SMC_CMD_COUNT, NULL, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call(dev, SANDBOX_SMC_CMD_COMMON, &val, ®s); + ut_asserteq(ret, 0); + ut_asserteq(val, 0); + + ret = sm_call_write(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_COUNT, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, SZ_4K + 1, + SANDBOX_SMC_CMD_WRITE_MEM, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_COUNT, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, SZ_4K + 1, + SANDBOX_SMC_CMD_READ_MEM, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, test_string, sizeof(test_string), + SANDBOX_SMC_CMD_WRITE_MEM, ®s); + ut_asserteq(ret, sizeof(test_string)); + + ret = sm_call_read(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_READ_MEM, ®s); + ut_asserteq(ret, sizeof(buffer)); + + ut_asserteq_str(buffer, test_string); + + return 0; +} + +DM_TEST(dm_test_sm, UT_TESTF_SCAN_FDT); -- 2.25.1
[PATCH v3 5/8] sandbox: defconfig: enable CONFIG_SM option
We use this option to test UCLASS_SM. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- configs/sandbox_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index be46cae7aa..0745a4ecca 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -270,6 +270,7 @@ CONFIG_RTC_RV8803=y CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_SANDBOX_SERIAL=y +CONFIG_SM=y CONFIG_SMEM=y CONFIG_SANDBOX_SMEM=y CONFIG_SOUND=y -- 2.25.1
[PATCH v3 6/8] drivers: introduce Meson Secure Monitor driver
This patch adds an implementation of the Meson Secure Monitor driver based on UCLASS_SM. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- MAINTAINERS | 1 + drivers/sm/Kconfig| 7 ++ drivers/sm/Makefile | 1 + drivers/sm/meson-sm.c | 198 ++ include/meson/sm.h| 19 5 files changed, 226 insertions(+) create mode 100644 drivers/sm/meson-sm.c create mode 100644 include/meson/sm.h diff --git a/MAINTAINERS b/MAINTAINERS index 6c64427782..bdc364fd4c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -158,6 +158,7 @@ F: drivers/net/phy/meson-gxl.c F: drivers/adc/meson-saradc.c F: drivers/phy/meson* F: drivers/mmc/meson_gx_mmc.c +F: drivers/sm/meson-sm.c F: drivers/spi/meson_spifc.c F: drivers/pinctrl/meson/ F: drivers/power/domain/meson-gx-pwrc-vpu.c diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig index 6cc6d55578..b4cc3f768e 100644 --- a/drivers/sm/Kconfig +++ b/drivers/sm/Kconfig @@ -1,2 +1,9 @@ config SM bool "Enable Secure Monitor driver support" + +config MESON_SM + bool "Amlogic Secure Monitor driver" + depends on SM + default n + help + Say y here to enable the Amlogic secure monitor driver. diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile index af5f475c2b..da81ee898a 100644 --- a/drivers/sm/Makefile +++ b/drivers/sm/Makefile @@ -2,3 +2,4 @@ obj-y += sm-uclass.o obj-$(CONFIG_SANDBOX) += sandbox-sm.o +obj-$(CONFIG_MESON_SM) += meson-sm.o diff --git a/drivers/sm/meson-sm.c b/drivers/sm/meson-sm.c new file mode 100644 index 00..25adaf4560 --- /dev/null +++ b/drivers/sm/meson-sm.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct meson_sm_cmd { + u32 smc_id; +}; + +#define SET_CMD(index, id) \ + [index] = { \ + .smc_id = (id), \ + } + +struct meson_sm_data { + u32 cmd_get_shmem_in; + u32 cmd_get_shmem_out; + unsigned int shmem_size; + struct meson_sm_cmd cmd[]; +}; + +struct meson_sm_priv { + void *sm_shmem_in; + void *sm_shmem_out; + const struct meson_sm_data *data; +}; + +static unsigned long __meson_sm_call(u32 cmd, const struct pt_regs *args) +{ + struct pt_regs r = *args; + + r.regs[0] = cmd; + smc_call(&r); + + return r.regs[0]; +}; + +static u32 meson_sm_get_cmd(const struct meson_sm_data *data, + u32 cmd_index) +{ + struct meson_sm_cmd cmd; + + if (cmd_index >= MESON_SMC_CMD_COUNT) + return 0; + + cmd = data->cmd[cmd_index]; + return cmd.smc_id; +} + +static int meson_sm_call(struct udevice *dev, u32 cmd_index, s32 *retval, +struct pt_regs *args) +{ + struct meson_sm_priv *priv = dev_get_priv(dev); + u32 cmd, ret; + + cmd = meson_sm_get_cmd(priv->data, cmd_index); + if (!cmd) + return -ENOENT; + + ret = __meson_sm_call(cmd, args); + if (retval) + *retval = ret; + + return 0; +} + +static int meson_sm_call_read(struct udevice *dev, void *buffer, size_t size, + u32 cmd_index, struct pt_regs *args) +{ + struct meson_sm_priv *priv = dev_get_priv(dev); + s32 nbytes; + int ret; + + if (!buffer || size > priv->data->shmem_size) + return -EINVAL; + + ret = meson_sm_call(dev, cmd_index, &nbytes, args); + if (ret) + return ret; + + if (nbytes < 0 || nbytes > size) + return -ENOBUFS; + + /* In some cases (for example GET_CHIP_ID command), +* SMC doesn't return the number of bytes read, even +* though the bytes were actually read into sm_shmem_out. +* So this check is needed. +*/ + ret = nbytes; + if (!nbytes) + nbytes = size; + + memcpy(buffer, priv->sm_shmem_out, nbytes); + + return ret; +} + +static int meson_sm_call_write(struct udevice *dev, void *buffer, size_t size, + u32 cmd_index, struct pt_regs *args) +{ + struct meson_sm_priv *priv = dev_get_priv(dev); + s32 nbytes; + int ret; + + if (!buffer || size > priv->data->shmem_size) + return -EINVAL; + + memcpy(priv->sm_shmem_in, buffer, size); + + ret = meson_sm_call(dev, cmd_index, &nbytes, args); + if (ret) + return ret; + + if (nbytes <= 0 || nbytes > size) + return -EIO; + + return nbytes; +} + +static int meson_sm_probe(struct udevice *dev) +{ + struct meson_sm_priv *p
[PATCH v3 7/8] arch: meson: sm: set correct order of the includes
The common.h header should always be first, followed by other headers in order, then headers with directories, then local files. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- arch/arm/mach-meson/sm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index d600c64d0b..b5dd6c6d39 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -6,7 +6,10 @@ */ #include +#include #include +#include +#include #include #include #include @@ -14,10 +17,7 @@ #include #include #include -#include #include -#include -#include #define FN_GET_SHARE_MEM_INPUT_BASE0x8220 #define FN_GET_SHARE_MEM_OUTPUT_BASE 0x8221 -- 2.25.1
[PATCH v3 8/8] arch: meson: use secure monitor driver
Now we have to use UCLASS_SM driver instead of raw smc_call() function call. Signed-off-by: Alexey Romanov Reviewed-by: Simon Glass --- arch/arm/mach-meson/Kconfig | 1 + arch/arm/mach-meson/sm.c| 110 +++- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 669ca09a00..d6c8905806 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -11,6 +11,7 @@ config MESON64_COMMON select PWRSEQ select MMC_PWRSEQ select BOARD_LATE_INIT + select MESON_SM imply CMD_DM config MESON_GX diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index b5dd6c6d39..914fd11c98 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,70 +19,62 @@ #include #include #include +#include -#define FN_GET_SHARE_MEM_INPUT_BASE0x8220 -#define FN_GET_SHARE_MEM_OUTPUT_BASE 0x8221 -#define FN_EFUSE_READ 0x8230 -#define FN_EFUSE_WRITE 0x8231 -#define FN_CHIP_ID 0x8244 -#define FN_PWRDM_SET 0x8293 - -static void *shmem_input; -static void *shmem_output; - -static void meson_init_shmem(void) +static inline struct udevice *meson_get_sm_device(void) { - struct pt_regs regs; - - if (shmem_input && shmem_output) - return; + struct udevice *dev; + int err; - regs.regs[0] = FN_GET_SHARE_MEM_INPUT_BASE; - smc_call(®s); - shmem_input = (void *)regs.regs[0]; - - regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE; - smc_call(®s); - shmem_output = (void *)regs.regs[0]; + err = uclass_first_device_err(UCLASS_SM, &dev); + if (err) { + pr_err("Mesom SM device not found\n"); + return ERR_PTR(err); + } - debug("Secure Monitor shmem: 0x%p 0x%p\n", shmem_input, shmem_output); + return dev; } ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size) { - struct pt_regs regs; + struct udevice *dev; + struct pt_regs regs = { 0 }; + int err; - meson_init_shmem(); + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); - regs.regs[0] = FN_EFUSE_READ; regs.regs[1] = offset; regs.regs[2] = size; - smc_call(®s); + err = sm_call_read(dev, buffer, size, + MESON_SMC_CMD_EFUSE_READ, ®s); + if (err < 0) + pr_err("Failed to read efuse memory (%d)\n", err); - if (regs.regs[0] == 0) - return -1; - - memcpy(buffer, shmem_output, min(size, regs.regs[0])); - - return regs.regs[0]; + return err; } ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size) { - struct pt_regs regs; - - meson_init_shmem(); + struct udevice *dev; + struct pt_regs regs = { 0 }; + int err; -memcpy(shmem_input, buffer, size); + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); - regs.regs[0] = FN_EFUSE_WRITE; regs.regs[1] = offset; regs.regs[2] = size; - smc_call(®s); + err = sm_call_write(dev, buffer, size, + MESON_SMC_CMD_EFUSE_WRITE, ®s); + if (err < 0) + pr_err("Failed to write efuse memory (%d)\n", err); - return regs.regs[0]; + return err; } #define SM_CHIP_ID_LENGTH 119 @@ -90,18 +83,21 @@ ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size) int meson_sm_get_serial(void *buffer, size_t size) { - struct pt_regs regs; + struct udevice *dev; + struct pt_regs regs = { 0 }; + u8 id_buffer[SM_CHIP_ID_LENGTH]; + int err; - meson_init_shmem(); + dev = meson_get_sm_device(); + if (IS_ERR(dev)) + return PTR_ERR(dev); - regs.regs[0] = FN_CHIP_ID; - regs.regs[1] = 0; - regs.regs[2] = 0; + err = sm_call_read(dev, id_buffer, SM_CHIP_ID_LENGTH, + MESON_SMC_CMD_CHIP_ID_GET, ®s); + if (err < 0) + pr_err("Failed to read serial number (%d)\n", err); - smc_call(®s); - - memcpy(buffer, shmem_output + SM_CHIP_ID_OFFSET, - min_t(size_t, size, SM_CHIP_ID_SIZE)); + memcpy(buffer, id_buffer + SM_CHIP_ID_OFFSET, size); return 0; } @@ -141,13 +137,21 @@ int meson_sm_get_reboot_reason(void) int meson_sm_pwrdm_set(size_t index, int cmd) { - struct pt_regs regs; + struct udevice *dev; + struct pt_regs regs = { 0 }; + int err; + + dev = meson_get_s
[PATCH v1 0/8] Support USB for Meson A1
Hello! This patchset adds USB stack support for Amlogic A1 SoC's series. Made reset / phy / dwc3 drivers more flexible and added support for A1 board. Alexey Romanov (7): dt-bindings: reset: add Meson A1 reset bindings reset: add support for Amlogic A1 family phy: get rid of raw hex values phy: move clk enable/disable in init/exit phy: support Amlogic A1 family dwc3: add support for Amlogic A1 family arch: a1: introduce USB initialization functionality Igor Prusov (1): a1: clk: Add missing CLKID_USB_PHY_IN gate arch/arm/mach-meson/board-a1.c| 89 +++ drivers/clk/meson/a1.c| 3 + drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 233 -- drivers/reset/reset-meson.c | 42 +++- drivers/usb/dwc3/dwc3-meson-g12a.c| 73 +- .../reset/amlogic,meson-a1-reset.h| 76 ++ 7 files changed, 484 insertions(+), 34 deletions(-) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h -- 2.25.1
[PATCH v1 2/8] reset: add support for Amlogic A1 family
This patch adds reset support for the Amlogic A1 family. We add the structure meson_reset_drvdata, which in the future will allow this driver to be used for other families by declaring only the correct parameters reg_count and level_offset. Signed-off-by: Alexey Romanov --- drivers/reset/reset-meson.c | 42 +++-- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 64bc696f13..9d0c8b354f 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -13,18 +13,26 @@ #include #include #include +#include -#define REG_COUNT 8 #define BITS_PER_REG 32 -#define LEVEL_OFFSET 0x7c + +struct meson_reset_drvdata { + unsigned int reg_count; + unsigned int level_offset; +}; struct meson_reset_priv { struct regmap *regmap; + struct meson_reset_drvdata *drvdata; }; static int meson_reset_request(struct reset_ctl *reset_ctl) { - if (reset_ctl->id > (REG_COUNT * BITS_PER_REG)) + struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; + + if (reset_ctl->id > (data->reg_count * BITS_PER_REG)) return -EINVAL; return 0; @@ -33,9 +41,10 @@ static int meson_reset_request(struct reset_ctl *reset_ctl) static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) { struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; uint bank = reset_ctl->id / BITS_PER_REG; uint offset = reset_ctl->id % BITS_PER_REG; - uint reg_offset = LEVEL_OFFSET + (bank << 2); + uint reg_offset = data->level_offset + (bank << 2); uint val; regmap_read(priv->regmap, reg_offset, &val); @@ -64,15 +73,36 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, }; +static const struct meson_reset_drvdata meson_gxbb_data = { + .reg_count = 8, + .level_offset = 0x7c, +}; + +static const struct meson_reset_drvdata meson_a1_data = { + .reg_count = 3, + .level_offset = 0x40, +}; + static const struct udevice_id meson_reset_ids[] = { - { .compatible = "amlogic,meson-gxbb-reset" }, - { .compatible = "amlogic,meson-axg-reset" }, + { + .compatible = "amlogic,meson-gxbb-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-axg-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-a1-reset", + .data = (ulong)&meson_a1_data, + }, { } }; static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev); + priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev); return regmap_init_mem(dev_ofnode(dev), &priv->regmap); } -- 2.25.1
[PATCH v1 1/8] dt-bindings: reset: add Meson A1 reset bindings
Get this from Linux 6.6-rc3. Signed-off-by: Alexey Romanov --- .../reset/amlogic,meson-a1-reset.h| 76 +++ 1 file changed, 76 insertions(+) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h diff --git a/include/dt-bindings/reset/amlogic,meson-a1-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-reset.h new file mode 100644 index 00..2c749c655e --- /dev/null +++ b/include/dt-bindings/reset/amlogic,meson-a1-reset.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen + * + * Copyright (c) 2023, SberDevices, Inc. + * Author: Alexey Romanov + */ + +#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H +#define _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H + +/* RESET0 */ +/* 0 */ +#define RESET_AM2AXI_VAD 1 +/* 2-3 */ +#define RESET_PSRAM4 +#define RESET_PAD_CTRL 5 +/* 6 */ +#define RESET_TEMP_SENSOR 7 +#define RESET_AM2AXI_DEV 8 +/* 9 */ +#define RESET_SPICC_A 10 +#define RESET_MSR_CLK 11 +#define RESET_AUDIO12 +#define RESET_ANALOG_CTRL 13 +#define RESET_SAR_ADC 14 +#define RESET_AUDIO_VAD15 +#define RESET_CEC 16 +#define RESET_PWM_EF 17 +#define RESET_PWM_CD 18 +#define RESET_PWM_AB 19 +/* 20 */ +#define RESET_IR_CTRL 21 +#define RESET_I2C_S_A 22 +/* 23 */ +#define RESET_I2C_M_D 24 +#define RESET_I2C_M_C 25 +#define RESET_I2C_M_B 26 +#define RESET_I2C_M_A 27 +#define RESET_I2C_PROD_AHB 28 +#define RESET_I2C_PROD 29 +/* 30-31 */ + +/* RESET1 */ +#define RESET_ACODEC 32 +#define RESET_DMA 33 +#define RESET_SD_EMMC_A34 +/* 35 */ +#define RESET_USBCTRL 36 +/* 37 */ +#define RESET_USBPHY 38 +/* 39-41 */ +#define RESET_RSA 42 +#define RESET_DMC 43 +/* 44 */ +#define RESET_IRQ_CTRL 45 +/* 46 */ +#define RESET_NIC_VAD 47 +#define RESET_NIC_AXI 48 +#define RESET_RAMA 49 +#define RESET_RAMB 50 +/* 51-52 */ +#define RESET_ROM 53 +#define RESET_SPIFC54 +#define RESET_GIC 55 +#define RESET_UART_C 56 +#define RESET_UART_B 57 +#define RESET_UART_A 58 +#define RESET_OSC_RING 59 +/* 60-63 */ + +/* RESET2 */ +/* 64-95 */ + +#endif -- 2.25.1
[PATCH v1 4/8] phy: move clk enable/disable in init/exit
It is better to place clk_enable() in phy_meson_g12a_usb2_init() and clk_disable() in phy_meson_g12a_usb2_exit(). For more detailed information, please see comments in the review of a similar driver in the Linux Kernel: https://lore.kernel.org/all/CAFBinCCEhobbyKHuKDWzTYCQWgNT1-e8=7hmhq1mvt6cueo...@mail.gmail.com/ Signed-off-by: Alexey Romanov --- drivers/phy/meson-g12a-usb2.c | 19 --- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 2e366b16ae..7b028784a0 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -160,6 +160,14 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret; +#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { + pr_err("failed to enable PHY clock\n"); + return ret; + } +#endif + ret = reset_assert(&priv->reset); udelay(1); ret |= reset_deassert(&priv->reset); @@ -252,6 +260,10 @@ static int phy_meson_g12a_usb2_exit(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret; +#if CONFIG_IS_ENABLED(CLK) + clk_disable(&priv->clk); +#endif + ret = reset_assert(&priv->reset); if (ret) return ret; @@ -289,13 +301,6 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - - ret = clk_enable(&priv->clk); - if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { - pr_err("failed to enable PHY clock\n"); - clk_free(&priv->clk); - return ret; - } #endif return 0; -- 2.25.1
[PATCH v1 6/8] a1: clk: Add missing CLKID_USB_PHY_IN gate
From: Igor Prusov We use this clock in dwc3 driver. Signed-off-by: Igor Prusov --- drivers/clk/meson/a1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c index 3aec42f33b..1540e1875b 100644 --- a/drivers/clk/meson/a1.c +++ b/drivers/clk/meson/a1.c @@ -238,6 +238,9 @@ static const struct meson_clk_info *meson_clocks[] = { [CLKID_FIXPLL_IN] = CLK_GATE("fixpll_in", A1_SYS_OSCIN_CTRL, 1, EXTERNAL_XTAL ), + [CLKID_USB_PHY_IN] = CLK_GATE("usb_phy_in", A1_SYS_OSCIN_CTRL, 2, + EXTERNAL_XTAL + ), [CLKID_SARADC] = CLK_GATE("saradc", A1_SAR_ADC_CLK_CTR, 8, -ENOENT ), -- 2.25.1
[PATCH v1 3/8] phy: get rid of raw hex values
It is better to use defines instead of write raw hex values in regmap. Signed-off-by: Alexey Romanov --- drivers/phy/meson-g12a-usb2.c | 161 -- 1 file changed, 153 insertions(+), 8 deletions(-) diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 650b88bd18..2e366b16ae 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -23,12 +23,28 @@ #include #include +#include #define PHY_CTRL_R00x0 #define PHY_CTRL_R10x4 #define PHY_CTRL_R20x8 + #define PHY_CTRL_R30xc + #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0) + #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2) + #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4) + #define PHY_CTRL_R40x10 + #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0) + #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8) + #define PHY_CTRL_R4_CALIB_CODE_23_16GENMASK(23, 16) + #define PHY_CTRL_R4_I_C2L_CAL_ENBIT(24) + #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25) + #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26) + #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30) + #define PHY_CTRL_R50x14 #define PHY_CTRL_R60x18 #define PHY_CTRL_R70x1c @@ -37,15 +53,93 @@ #define PHY_CTRL_R10 0x28 #define PHY_CTRL_R11 0x2c #define PHY_CTRL_R12 0x30 + #define PHY_CTRL_R13 0x34 + #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0) + #define PHY_CTRL_R13_LOAD_STAT BIT(14) + #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15) + #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16) + #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23) + #define PHY_CTRL_R13_I_C2L_HS_ENBIT(24) + #define PHY_CTRL_R13_I_C2L_FS_ENBIT(25) + #define PHY_CTRL_R13_I_C2L_LS_ENBIT(26) + #define PHY_CTRL_R13_I_C2L_HS_OEBIT(27) + #define PHY_CTRL_R13_I_C2L_FS_OEBIT(28) + #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29) + #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30) + #define PHY_CTRL_R14 0x38 #define PHY_CTRL_R15 0x3c + #define PHY_CTRL_R16 0x40 + #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0) + #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10) + #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20) + #define PHY_CTRL_R16_MPLL_SDM_ENBIT(21) + #define PHY_CTRL_R16_MPLL_LOAD BIT(22) + #define PHY_CTRL_R16_MPLL_DCO_SDM_ENBIT(23) + #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24) + #define PHY_CTRL_R16_MPLL_LOCK_FBIT(26) + #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27) + #define PHY_CTRL_R16_MPLL_ENBIT(28) + #define PHY_CTRL_R16_MPLL_RESET BIT(29) + #define PHY_CTRL_R16_MPLL_LOCK BIT(30) + #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31) + #define PHY_CTRL_R17 0x44 + #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0) + #define PHY_CTRL_R17_MPLL_FIX_ENBIT(16) + #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17) + #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20) + #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23) + #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24) + #define
[PATCH v1 5/8] phy: support Amlogic A1 family
Setting G12A and A1 is similar, so we can use G12A phy driver with little changes. Signed-off-by: Alexey Romanov --- drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 77 --- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index cf4d5908d7..60be62907d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -190,7 +190,7 @@ config MESON_GXL_USB_PHY config MESON_G12A_USB_PHY bool "Amlogic Meson G12A USB PHYs" - depends on PHY && ARCH_MESON && MESON_G12A + depends on PHY && ARCH_MESON && (MESON_G12A || MESON_A1) imply REGMAP help This is the generic phy driver for the Amlogic Meson G12A diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 7b028784a0..c1b9baa7b7 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -146,18 +147,28 @@ #define RESET_COMPLETE_TIME1000 #define PLL_RESET_COMPLETE_TIME100 +enum meson_soc_id { + MESON_SOC_A1, + MESON_SOC_G12A, +}; + struct phy_meson_g12a_usb2_priv { struct regmap *regmap; #if CONFIG_IS_ENABLED(CLK) struct clk clk; #endif struct reset_ctlreset; +#if CONFIG_IS_ENABLED(POWER_DOMAIN) + struct power_domain pwrdm; +#endif + int soc_id; }; static int phy_meson_g12a_usb2_init(struct phy *phy) { struct udevice *dev = phy->dev; struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); + u32 value; int ret; #if CONFIG_IS_ENABLED(CLK) @@ -196,8 +207,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); - regmap_write(priv->regmap, PHY_CTRL_R18, - FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | + value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | @@ -209,6 +219,11 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | PHY_CTRL_R18_MPLL_ACG_RANGE; + if (priv->soc_id == MESON_SOC_A1) + value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL; + + regmap_write(priv->regmap, PHY_CTRL_R18, value); + udelay(PLL_RESET_COMPLETE_TIME); /* UnReset PLL */ @@ -231,13 +246,19 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); - regmap_write(priv->regmap, PHY_CTRL_R4, - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | - PHY_CTRL_R4_TEST_BYPASS_MODE_EN | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + if (priv->soc_id == MESON_SOC_G12A) + regmap_write(priv->regmap, PHY_CTRL_R4, + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | + PHY_CTRL_R4_TEST_BYPASS_MODE_EN | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + else if (priv->soc_id == MESON_SOC_A1) + regmap_write(priv->regmap, PHY_CTRL_R21, + PHY_CTRL_R21_USB2_CAL_ACK_EN | + PHY_CTRL_R21_USB2_TX_STRG_PD | + FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2)); /* Tuning Disconnect Threshold */ regmap_write(priv->regmap, PHY_CTRL_R3, @@ -246,10 +267,15 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3)); /* Analog Settings */ - regmap_write(priv->regmap, PHY_CTRL_R14, 0); - regmap_write(priv->regmap, PHY_CTRL_R13, - PHY_CTRL_R13_UPDATE_PMA_SIGNALS | - FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + if (priv->soc_id == MESON_SOC_G12A) { + regmap_write(priv->regmap, PHY_CTRL_R14, 0); + regmap_write(priv->regmap, PHY_CTRL_R13, + PHY_CTRL_R13_UPDATE_PMA_SIGNALS | + FIELD_PREP(PH
[PATCH v1 7/8] dwc3: add support for Amlogic A1 family
Now the driver supports also A1 phy layer. Signed-off-by: Alexey Romanov --- drivers/usb/dwc3/dwc3-meson-g12a.c | 73 ++ 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 90418ddc1d..550e6682a2 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -28,6 +28,7 @@ #include #include #include +#include /* USB2 Ports Control Registers */ @@ -102,10 +103,22 @@ enum { PHY_COUNT, }; -static const char *phy_names[PHY_COUNT] = { +static const char *const dwc3_meson_g12a_phy_names[] = { "usb2-phy0", "usb2-phy1", "usb3-phy0", }; +static const char *const dwc3_meson_a1_phy_names[] = { + "usb2-phy0", "usb2-phy1" +}; + +struct dwc3_meson_g12a; + +struct dwc3_meson_g12a_drvdata { + const char *const *phy_names; + unsigned int phy_cnt; + int (*clk_init)(struct dwc3_meson_g12a *priv); +}; + struct dwc3_meson_g12a { struct udevice *dev; struct regmap *regmap; @@ -119,6 +132,7 @@ struct dwc3_meson_g12a { #if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vbus_supply; #endif + struct dwc3_meson_g12a_drvdata *drvdata; }; #define U2P_REG_SIZE 0x20 @@ -293,10 +307,11 @@ int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode) static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) { + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i, ret; - for (i = 0 ; i < PHY_COUNT ; ++i) { - ret = generic_phy_get_by_name(priv->dev, phy_names[i], + for (i = 0 ; i < data->phy_cnt; ++i) { + ret = generic_phy_get_by_name(priv->dev, data->phy_names[i], &priv->phys[i]); if (ret == -ENOENT || ret == -ENODATA) continue; @@ -354,18 +369,36 @@ static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv) return 0; } +static int dwc3_meson_a1_clk_init(struct dwc3_meson_g12a *priv) +{ + int ret; + + ret = clk_get_by_name(priv->dev, "usb_bus", &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + return 0; +} + static int dwc3_meson_g12a_probe(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = + (struct dwc3_meson_g12a_drvdata *)dev_get_driver_data(dev); int ret, i; + priv->drvdata = data; priv->dev = dev; ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret; - ret = dwc3_meson_g12a_clk_init(priv); + ret = data->clk_init(priv); if (ret) return ret; @@ -398,7 +431,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) if (ret) return ret; - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -407,7 +440,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) goto err_phy_init; } - for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -419,7 +452,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) return 0; err_phy_init: - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt ; ++i) { if (!priv->phys[i].dev) continue; @@ -432,20 +465,21 @@ err_phy_init: static int dwc3_meson_g12a_remove(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i; reset_release_all(&priv->reset, 1); clk_release_all(&priv->clk, 1); - for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; generic_phy_power_off(&priv->phys[i]); } - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -455,8 +489,27 @@ static int dwc3_meson_g12a_remove(struct udevice *dev) return dm_scan_fdt_dev(dev); } +static const struct dwc3_meson_g12a_drvdata meson_g12a_drvdata = { + .phy_names = dwc3_meson_g12a_
[PATCH v1 8/8] arch: a1: introduce USB initialization functionality
This is entrypoint for USB stack initialization. Function board_usb_init will be called from cmd/fastboot.c code. Signed-off-by: Alexey Romanov --- arch/arm/mach-meson/board-a1.c | 89 ++ 1 file changed, 89 insertions(+) diff --git a/arch/arm/mach-meson/board-a1.c b/arch/arm/mach-meson/board-a1.c index 967bb67182..781d5cfb33 100644 --- a/arch/arm/mach-meson/board-a1.c +++ b/arch/arm/mach-meson/board-a1.c @@ -4,12 +4,17 @@ */ #include +#include +#include #include #include #include #include #include #include +#include +#include +#include phys_size_t get_effective_memsize(void) { @@ -57,3 +62,87 @@ static struct mm_region a1_mem_map[] = { }; struct mm_region *mem_map = a1_mem_map; + +#if CONFIG_IS_ENABLED(USB_DWC3_MESON_G12A) && \ + CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG) + +static struct dwc2_plat_otg_data meson_a1_dwc2_data; + +int board_usb_init(int index, enum usb_init_type init) +{ + int node, dwc2_node; + const void *blob = gd->fdt_blob; + struct udevice *dev; + int ret; + + node = fdt_node_offset_by_compatible(blob, -1, +"amlogic,meson-a1-usb-ctrl"); + if (node < 0) { + pr_err("not found usb-control node\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, node)) { + pr_err("usb is disabled in the device tree\n"); + return -ENODEV; + } + + ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev); + if (ret) { + pr_err("not found usb-control device\n"); + return ret; + } + + dwc2_node = fdt_node_offset_by_compatible(blob, node, + "amlogic,meson-a1-usb"); + if (dwc2_node < 0) { + pr_err("not found dwc2 node\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, dwc2_node)) { + pr_err("dwc2 is disabled in the device tree\n"); + return -ENODEV; + } + + meson_a1_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg"); + if (meson_a1_dwc2_data.regs_otg == FDT_ADDR_T_NONE) { + pr_err("can't get base address\n"); + return -ENODATA; + } + + meson_a1_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-rx-fifo-size", 0); + if (meson_a1_dwc2_data.rx_fifo_sz < 0) { + pr_err("failed to get g-rx-fifo-size value\n"); + return -ENODATA; + } + + meson_a1_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-np-tx-fifo-size", 0); + if (meson_a1_dwc2_data.np_tx_fifo_sz < 0) { + pr_err("failed to get g-np-tx-fifo-size value\n"); + return -ENODATA; + } + + meson_a1_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-tx-fifo-size", 0); + if (meson_a1_dwc2_data.tx_fifo_sz < 0) { + pr_err("failed to get g-tx-fifo-size value\n"); + return -ENODATA; + } + + ret = dwc3_meson_g12a_force_mode(dev, USB_DR_MODE_PERIPHERAL); + if (ret) { + pr_err("failed to force usb mode to peripheral\n"); + return ret; + } + + return dwc2_udc_probe(&meson_a1_dwc2_data); +} + +int board_usb_cleanup(int index, enum usb_init_type init) +{ + return 0; +} +#endif -- 2.25.1
[PATCH v2 0/8] Support USB for Meson A1
Hello! This patchset adds USB stack support for Amlogic A1 SoC's series. Made reset / phy / dwc3 drivers more flexible and added support for A1 board. V2: - Made power domain for PHY optional. - Add missing CLKID_USB_PHY gate. - Drop patch with USB stack initialization in board-a1.c. Instead of, enable CONFIG_DM_USB_GADGET for AD401 board. - Support A1 in g12a_child_pre_probe/post_remove functions in dwc3 driver. Alexey Romanov (7): dt-bindings: reset: add Meson A1 reset bindings reset: add support for Amlogic A1 family phy: get rid of raw hex values phy: move clk enable/disable in init/exit phy: support Amlogic A1 family dwc3: add support for Amlogic A1 family ad401: enable USB stack Igor Prusov (1): a1: clk: Add missing USB_PHY_IN and USB_PHY gates configs/ad401_defconfig | 3 + drivers/clk/meson/a1.c| 6 + drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 235 -- drivers/reset/reset-meson.c | 42 +++- drivers/usb/dwc3/dwc3-meson-g12a.c| 73 +- .../reset/amlogic,meson-a1-reset.h| 76 ++ 7 files changed, 403 insertions(+), 34 deletions(-) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h -- 2.25.1
[PATCH v2 1/8] dt-bindings: reset: add Meson A1 reset bindings
Get this from Linux 6.6-rc3. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- .../reset/amlogic,meson-a1-reset.h| 76 +++ 1 file changed, 76 insertions(+) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h diff --git a/include/dt-bindings/reset/amlogic,meson-a1-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-reset.h new file mode 100644 index 00..2c749c655e --- /dev/null +++ b/include/dt-bindings/reset/amlogic,meson-a1-reset.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen + * + * Copyright (c) 2023, SberDevices, Inc. + * Author: Alexey Romanov + */ + +#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H +#define _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H + +/* RESET0 */ +/* 0 */ +#define RESET_AM2AXI_VAD 1 +/* 2-3 */ +#define RESET_PSRAM4 +#define RESET_PAD_CTRL 5 +/* 6 */ +#define RESET_TEMP_SENSOR 7 +#define RESET_AM2AXI_DEV 8 +/* 9 */ +#define RESET_SPICC_A 10 +#define RESET_MSR_CLK 11 +#define RESET_AUDIO12 +#define RESET_ANALOG_CTRL 13 +#define RESET_SAR_ADC 14 +#define RESET_AUDIO_VAD15 +#define RESET_CEC 16 +#define RESET_PWM_EF 17 +#define RESET_PWM_CD 18 +#define RESET_PWM_AB 19 +/* 20 */ +#define RESET_IR_CTRL 21 +#define RESET_I2C_S_A 22 +/* 23 */ +#define RESET_I2C_M_D 24 +#define RESET_I2C_M_C 25 +#define RESET_I2C_M_B 26 +#define RESET_I2C_M_A 27 +#define RESET_I2C_PROD_AHB 28 +#define RESET_I2C_PROD 29 +/* 30-31 */ + +/* RESET1 */ +#define RESET_ACODEC 32 +#define RESET_DMA 33 +#define RESET_SD_EMMC_A34 +/* 35 */ +#define RESET_USBCTRL 36 +/* 37 */ +#define RESET_USBPHY 38 +/* 39-41 */ +#define RESET_RSA 42 +#define RESET_DMC 43 +/* 44 */ +#define RESET_IRQ_CTRL 45 +/* 46 */ +#define RESET_NIC_VAD 47 +#define RESET_NIC_AXI 48 +#define RESET_RAMA 49 +#define RESET_RAMB 50 +/* 51-52 */ +#define RESET_ROM 53 +#define RESET_SPIFC54 +#define RESET_GIC 55 +#define RESET_UART_C 56 +#define RESET_UART_B 57 +#define RESET_UART_A 58 +#define RESET_OSC_RING 59 +/* 60-63 */ + +/* RESET2 */ +/* 64-95 */ + +#endif -- 2.25.1
[PATCH v2 2/8] reset: add support for Amlogic A1 family
This patch adds reset support for the Amlogic A1 family. We add the structure meson_reset_drvdata, which in the future will allow this driver to be used for other families by declaring only the correct parameters reg_count and level_offset. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/reset/reset-meson.c | 42 +++-- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 64bc696f13..9d0c8b354f 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -13,18 +13,26 @@ #include #include #include +#include -#define REG_COUNT 8 #define BITS_PER_REG 32 -#define LEVEL_OFFSET 0x7c + +struct meson_reset_drvdata { + unsigned int reg_count; + unsigned int level_offset; +}; struct meson_reset_priv { struct regmap *regmap; + struct meson_reset_drvdata *drvdata; }; static int meson_reset_request(struct reset_ctl *reset_ctl) { - if (reset_ctl->id > (REG_COUNT * BITS_PER_REG)) + struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; + + if (reset_ctl->id > (data->reg_count * BITS_PER_REG)) return -EINVAL; return 0; @@ -33,9 +41,10 @@ static int meson_reset_request(struct reset_ctl *reset_ctl) static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) { struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; uint bank = reset_ctl->id / BITS_PER_REG; uint offset = reset_ctl->id % BITS_PER_REG; - uint reg_offset = LEVEL_OFFSET + (bank << 2); + uint reg_offset = data->level_offset + (bank << 2); uint val; regmap_read(priv->regmap, reg_offset, &val); @@ -64,15 +73,36 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, }; +static const struct meson_reset_drvdata meson_gxbb_data = { + .reg_count = 8, + .level_offset = 0x7c, +}; + +static const struct meson_reset_drvdata meson_a1_data = { + .reg_count = 3, + .level_offset = 0x40, +}; + static const struct udevice_id meson_reset_ids[] = { - { .compatible = "amlogic,meson-gxbb-reset" }, - { .compatible = "amlogic,meson-axg-reset" }, + { + .compatible = "amlogic,meson-gxbb-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-axg-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-a1-reset", + .data = (ulong)&meson_a1_data, + }, { } }; static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev); + priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev); return regmap_init_mem(dev_ofnode(dev), &priv->regmap); } -- 2.25.1
[PATCH v2 3/8] phy: get rid of raw hex values
It is better to use defines instead of write raw hex values in regmap. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/phy/meson-g12a-usb2.c | 161 -- 1 file changed, 153 insertions(+), 8 deletions(-) diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 650b88bd18..2e366b16ae 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -23,12 +23,28 @@ #include #include +#include #define PHY_CTRL_R00x0 #define PHY_CTRL_R10x4 #define PHY_CTRL_R20x8 + #define PHY_CTRL_R30xc + #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0) + #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2) + #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4) + #define PHY_CTRL_R40x10 + #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0) + #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8) + #define PHY_CTRL_R4_CALIB_CODE_23_16GENMASK(23, 16) + #define PHY_CTRL_R4_I_C2L_CAL_ENBIT(24) + #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25) + #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26) + #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30) + #define PHY_CTRL_R50x14 #define PHY_CTRL_R60x18 #define PHY_CTRL_R70x1c @@ -37,15 +53,93 @@ #define PHY_CTRL_R10 0x28 #define PHY_CTRL_R11 0x2c #define PHY_CTRL_R12 0x30 + #define PHY_CTRL_R13 0x34 + #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0) + #define PHY_CTRL_R13_LOAD_STAT BIT(14) + #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15) + #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16) + #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23) + #define PHY_CTRL_R13_I_C2L_HS_ENBIT(24) + #define PHY_CTRL_R13_I_C2L_FS_ENBIT(25) + #define PHY_CTRL_R13_I_C2L_LS_ENBIT(26) + #define PHY_CTRL_R13_I_C2L_HS_OEBIT(27) + #define PHY_CTRL_R13_I_C2L_FS_OEBIT(28) + #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29) + #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30) + #define PHY_CTRL_R14 0x38 #define PHY_CTRL_R15 0x3c + #define PHY_CTRL_R16 0x40 + #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0) + #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10) + #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20) + #define PHY_CTRL_R16_MPLL_SDM_ENBIT(21) + #define PHY_CTRL_R16_MPLL_LOAD BIT(22) + #define PHY_CTRL_R16_MPLL_DCO_SDM_ENBIT(23) + #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24) + #define PHY_CTRL_R16_MPLL_LOCK_FBIT(26) + #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27) + #define PHY_CTRL_R16_MPLL_ENBIT(28) + #define PHY_CTRL_R16_MPLL_RESET BIT(29) + #define PHY_CTRL_R16_MPLL_LOCK BIT(30) + #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31) + #define PHY_CTRL_R17 0x44 + #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0) + #define PHY_CTRL_R17_MPLL_FIX_ENBIT(16) + #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17) + #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20) + #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23) + #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24
[PATCH v2 5/8] phy: support Amlogic A1 family
Setting G12A and A1 is similar, so we can use G12A phy driver with little changes. Signed-off-by: Alexey Romanov --- drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 79 --- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index cf4d5908d7..60be62907d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -190,7 +190,7 @@ config MESON_GXL_USB_PHY config MESON_G12A_USB_PHY bool "Amlogic Meson G12A USB PHYs" - depends on PHY && ARCH_MESON && MESON_G12A + depends on PHY && ARCH_MESON && (MESON_G12A || MESON_A1) imply REGMAP help This is the generic phy driver for the Amlogic Meson G12A diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 7b028784a0..90053dbea3 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -146,18 +147,28 @@ #define RESET_COMPLETE_TIME1000 #define PLL_RESET_COMPLETE_TIME100 +enum meson_soc_id { + MESON_SOC_A1, + MESON_SOC_G12A, +}; + struct phy_meson_g12a_usb2_priv { struct regmap *regmap; #if CONFIG_IS_ENABLED(CLK) struct clk clk; #endif struct reset_ctlreset; +#if CONFIG_IS_ENABLED(POWER_DOMAIN) + struct power_domain pwrdm; +#endif + int soc_id; }; static int phy_meson_g12a_usb2_init(struct phy *phy) { struct udevice *dev = phy->dev; struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); + u32 value; int ret; #if CONFIG_IS_ENABLED(CLK) @@ -196,8 +207,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); - regmap_write(priv->regmap, PHY_CTRL_R18, - FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | + value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | @@ -209,6 +219,11 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | PHY_CTRL_R18_MPLL_ACG_RANGE; + if (priv->soc_id == MESON_SOC_A1) + value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL; + + regmap_write(priv->regmap, PHY_CTRL_R18, value); + udelay(PLL_RESET_COMPLETE_TIME); /* UnReset PLL */ @@ -231,13 +246,19 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); - regmap_write(priv->regmap, PHY_CTRL_R4, - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | - PHY_CTRL_R4_TEST_BYPASS_MODE_EN | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + if (priv->soc_id == MESON_SOC_G12A) + regmap_write(priv->regmap, PHY_CTRL_R4, + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | + PHY_CTRL_R4_TEST_BYPASS_MODE_EN | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + else if (priv->soc_id == MESON_SOC_A1) + regmap_write(priv->regmap, PHY_CTRL_R21, + PHY_CTRL_R21_USB2_CAL_ACK_EN | + PHY_CTRL_R21_USB2_TX_STRG_PD | + FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2)); /* Tuning Disconnect Threshold */ regmap_write(priv->regmap, PHY_CTRL_R3, @@ -246,10 +267,15 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3)); /* Analog Settings */ - regmap_write(priv->regmap, PHY_CTRL_R14, 0); - regmap_write(priv->regmap, PHY_CTRL_R13, - PHY_CTRL_R13_UPDATE_PMA_SIGNALS | - FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + if (priv->soc_id == MESON_SOC_G12A) { + regmap_write(priv->regmap, PHY_CTRL_R14, 0); + regmap_write(priv->regmap, PHY_CTRL_R13, + PHY_CTRL_R13_UPDATE_PMA_SIGNALS | + FIELD_PREP(PH
[PATCH v2 4/8] phy: move clk enable/disable in init/exit
It is better to place clk_enable() in phy_meson_g12a_usb2_init() and clk_disable() in phy_meson_g12a_usb2_exit(). For more detailed information, please see comments in the review of a similar driver in the Linux Kernel: https://lore.kernel.org/all/CAFBinCCEhobbyKHuKDWzTYCQWgNT1-e8=7hmhq1mvt6cueo...@mail.gmail.com/ Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/phy/meson-g12a-usb2.c | 19 --- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 2e366b16ae..7b028784a0 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -160,6 +160,14 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret; +#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { + pr_err("failed to enable PHY clock\n"); + return ret; + } +#endif + ret = reset_assert(&priv->reset); udelay(1); ret |= reset_deassert(&priv->reset); @@ -252,6 +260,10 @@ static int phy_meson_g12a_usb2_exit(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret; +#if CONFIG_IS_ENABLED(CLK) + clk_disable(&priv->clk); +#endif + ret = reset_assert(&priv->reset); if (ret) return ret; @@ -289,13 +301,6 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - - ret = clk_enable(&priv->clk); - if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { - pr_err("failed to enable PHY clock\n"); - clk_free(&priv->clk); - return ret; - } #endif return 0; -- 2.25.1
[PATCH v2 8/8] ad401: enable USB stack
Currently we have all drivers for use USB stack on A1-series SoC's. Let's enable USB options for the Amlogic AD401 reference A1 SoC board. Signed-off-by: Alexey Romanov --- configs/ad401_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configs/ad401_defconfig b/configs/ad401_defconfig index 529e553bac..b02ff47b7a 100644 --- a/configs/ad401_defconfig +++ b/configs/ad401_defconfig @@ -51,4 +51,7 @@ CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_MESON_SERIAL=y CONFIG_SPI=y CONFIG_DM_SPI=y +CONFIG_USB=y +CONFIG_DM_USB_GADGET=y +CONFIG_USB_GADGET=y CONFIG_WDT=y -- 2.25.1
[PATCH v2 6/8] a1: clk: Add missing USB_PHY_IN and USB_PHY gates
From: Igor Prusov We use this clocks in dwc3 driver. Signed-off-by: Igor Prusov Signed-off-by: Alexey Romanov --- drivers/clk/meson/a1.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c index 3aec42f33b..1075ba7333 100644 --- a/drivers/clk/meson/a1.c +++ b/drivers/clk/meson/a1.c @@ -238,6 +238,12 @@ static const struct meson_clk_info *meson_clocks[] = { [CLKID_FIXPLL_IN] = CLK_GATE("fixpll_in", A1_SYS_OSCIN_CTRL, 1, EXTERNAL_XTAL ), + [CLKID_USB_PHY_IN] = CLK_GATE("usb_phy_in", A1_SYS_OSCIN_CTRL, 2, + EXTERNAL_XTAL + ), + [CLKID_USB_PHY] = CLK_GATE("usb_phy", A1_SYS_CLK_EN0, 27, + CLKID_SYS + ), [CLKID_SARADC] = CLK_GATE("saradc", A1_SAR_ADC_CLK_CTR, 8, -ENOENT ), -- 2.25.1
[PATCH v2 7/8] dwc3: add support for Amlogic A1 family
Now the driver supports also A1 phy layer. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/usb/dwc3/dwc3-meson-g12a.c | 73 ++ 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 195670e4ca..5433ac0dca 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -28,6 +28,7 @@ #include #include #include +#include /* USB2 Ports Control Registers */ @@ -102,10 +103,22 @@ enum { PHY_COUNT, }; -static const char *phy_names[PHY_COUNT] = { +static const char *const dwc3_meson_g12a_phy_names[] = { "usb2-phy0", "usb2-phy1", "usb3-phy0", }; +static const char *const dwc3_meson_a1_phy_names[] = { + "usb2-phy0", "usb2-phy1" +}; + +struct dwc3_meson_g12a; + +struct dwc3_meson_g12a_drvdata { + const char *const *phy_names; + unsigned int phy_cnt; + int (*clk_init)(struct dwc3_meson_g12a *priv); +}; + struct dwc3_meson_g12a { struct udevice *dev; struct regmap *regmap; @@ -119,6 +132,7 @@ struct dwc3_meson_g12a { #if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vbus_supply; #endif + struct dwc3_meson_g12a_drvdata *drvdata; }; #define U2P_REG_SIZE 0x20 @@ -293,10 +307,11 @@ int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode) static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) { + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i, ret; - for (i = 0 ; i < PHY_COUNT ; ++i) { - ret = generic_phy_get_by_name(priv->dev, phy_names[i], + for (i = 0 ; i < data->phy_cnt; ++i) { + ret = generic_phy_get_by_name(priv->dev, data->phy_names[i], &priv->phys[i]); if (ret == -ENOENT || ret == -ENODATA) continue; @@ -354,18 +369,36 @@ static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv) return 0; } +static int dwc3_meson_a1_clk_init(struct dwc3_meson_g12a *priv) +{ + int ret; + + ret = clk_get_by_name(priv->dev, "usb_bus", &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + return 0; +} + static int dwc3_meson_g12a_probe(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = + (struct dwc3_meson_g12a_drvdata *)dev_get_driver_data(dev); int ret, i; + priv->drvdata = data; priv->dev = dev; ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret; - ret = dwc3_meson_g12a_clk_init(priv); + ret = data->clk_init(priv); if (ret) return ret; @@ -398,7 +431,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) if (ret) return ret; - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -407,7 +440,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) goto err_phy_init; } - for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -419,7 +452,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) return 0; err_phy_init: - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt ; ++i) { if (!priv->phys[i].dev) continue; @@ -432,20 +465,21 @@ err_phy_init: static int dwc3_meson_g12a_remove(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i; reset_release_all(&priv->reset, 1); clk_release_all(&priv->clk, 1); - for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; generic_phy_power_off(&priv->phys[i]); } - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -461,11 +495,20 @@ static const struct dwc3_meson_g12a_drvdata meson_g12a_drvdata = { .clk_init = dwc3_meson_g12a_clk_init, }; +static const struct dwc
[PATCH v1] drivers: sm: fix build warning
This fixes following warning during u-boot build: WARNING: unmet direct dependencies detected for MESON_SM Depends on [n]: SM [=n] Selected by [y]: - MESON64_COMMON [=y] && ARM [=y] && ARCH_MESON [=y] Fixes: 9849712e7655 ("drivers: introduce Meson Secure Monitor driver") Signed-off-by: Alexey Romanov Signed-off-by: Igor Prusov --- drivers/sm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig index b4cc3f768e..f0987275d2 100644 --- a/drivers/sm/Kconfig +++ b/drivers/sm/Kconfig @@ -3,7 +3,7 @@ config SM config MESON_SM bool "Amlogic Secure Monitor driver" - depends on SM + select SM default n help Say y here to enable the Amlogic secure monitor driver. -- 2.25.1
[PATCH v3 0/8] Support USB for Meson A1
Hello! This patchset adds USB stack support for Amlogic A1 SoC's series. Made reset / phy / dwc3 drivers more flexible and added support for A1 board. V2: - Made power domain for PHY optional. - Add missing CLKID_USB_PHY gate. - Drop patch with USB stack initialization in board-a1.c. Instead of, enable CONFIG_DM_USB_GADGET for AD401 board. - Support A1 in g12a_child_pre_probe/post_remove functions in dwc3 driver. V3: - Rebased over latests Amlogic U-Boot branch. Alexey Romanov (7): dt-bindings: reset: add Meson A1 reset bindings reset: add support for Amlogic A1 family phy: get rid of raw hex values phy: move clk enable/disable in init/exit phy: support Amlogic A1 family dwc3: add support for Amlogic A1 family ad401: enable USB stack Igor Prusov (1): a1: clk: Add missing USB_PHY_IN and USB_PHY gates configs/ad401_defconfig | 3 + drivers/clk/meson/a1.c| 6 + drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 235 -- drivers/reset/reset-meson.c | 42 +++- drivers/usb/dwc3/dwc3-meson-g12a.c| 79 +- .../reset/amlogic,meson-a1-reset.h| 76 ++ 7 files changed, 409 insertions(+), 34 deletions(-) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h -- 2.25.1
[PATCH v3 1/8] dt-bindings: reset: add Meson A1 reset bindings
Get this from Linux 6.6-rc3. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- .../reset/amlogic,meson-a1-reset.h| 76 +++ 1 file changed, 76 insertions(+) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h diff --git a/include/dt-bindings/reset/amlogic,meson-a1-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-reset.h new file mode 100644 index 00..2c749c655e --- /dev/null +++ b/include/dt-bindings/reset/amlogic,meson-a1-reset.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen + * + * Copyright (c) 2023, SberDevices, Inc. + * Author: Alexey Romanov + */ + +#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H +#define _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H + +/* RESET0 */ +/* 0 */ +#define RESET_AM2AXI_VAD 1 +/* 2-3 */ +#define RESET_PSRAM4 +#define RESET_PAD_CTRL 5 +/* 6 */ +#define RESET_TEMP_SENSOR 7 +#define RESET_AM2AXI_DEV 8 +/* 9 */ +#define RESET_SPICC_A 10 +#define RESET_MSR_CLK 11 +#define RESET_AUDIO12 +#define RESET_ANALOG_CTRL 13 +#define RESET_SAR_ADC 14 +#define RESET_AUDIO_VAD15 +#define RESET_CEC 16 +#define RESET_PWM_EF 17 +#define RESET_PWM_CD 18 +#define RESET_PWM_AB 19 +/* 20 */ +#define RESET_IR_CTRL 21 +#define RESET_I2C_S_A 22 +/* 23 */ +#define RESET_I2C_M_D 24 +#define RESET_I2C_M_C 25 +#define RESET_I2C_M_B 26 +#define RESET_I2C_M_A 27 +#define RESET_I2C_PROD_AHB 28 +#define RESET_I2C_PROD 29 +/* 30-31 */ + +/* RESET1 */ +#define RESET_ACODEC 32 +#define RESET_DMA 33 +#define RESET_SD_EMMC_A34 +/* 35 */ +#define RESET_USBCTRL 36 +/* 37 */ +#define RESET_USBPHY 38 +/* 39-41 */ +#define RESET_RSA 42 +#define RESET_DMC 43 +/* 44 */ +#define RESET_IRQ_CTRL 45 +/* 46 */ +#define RESET_NIC_VAD 47 +#define RESET_NIC_AXI 48 +#define RESET_RAMA 49 +#define RESET_RAMB 50 +/* 51-52 */ +#define RESET_ROM 53 +#define RESET_SPIFC54 +#define RESET_GIC 55 +#define RESET_UART_C 56 +#define RESET_UART_B 57 +#define RESET_UART_A 58 +#define RESET_OSC_RING 59 +/* 60-63 */ + +/* RESET2 */ +/* 64-95 */ + +#endif -- 2.25.1
[PATCH v3 2/8] reset: add support for Amlogic A1 family
This patch adds reset support for the Amlogic A1 family. We add the structure meson_reset_drvdata, which in the future will allow this driver to be used for other families by declaring only the correct parameters reg_count and level_offset. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/reset/reset-meson.c | 42 +++-- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 64bc696f13..9d0c8b354f 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -13,18 +13,26 @@ #include #include #include +#include -#define REG_COUNT 8 #define BITS_PER_REG 32 -#define LEVEL_OFFSET 0x7c + +struct meson_reset_drvdata { + unsigned int reg_count; + unsigned int level_offset; +}; struct meson_reset_priv { struct regmap *regmap; + struct meson_reset_drvdata *drvdata; }; static int meson_reset_request(struct reset_ctl *reset_ctl) { - if (reset_ctl->id > (REG_COUNT * BITS_PER_REG)) + struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; + + if (reset_ctl->id > (data->reg_count * BITS_PER_REG)) return -EINVAL; return 0; @@ -33,9 +41,10 @@ static int meson_reset_request(struct reset_ctl *reset_ctl) static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) { struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; uint bank = reset_ctl->id / BITS_PER_REG; uint offset = reset_ctl->id % BITS_PER_REG; - uint reg_offset = LEVEL_OFFSET + (bank << 2); + uint reg_offset = data->level_offset + (bank << 2); uint val; regmap_read(priv->regmap, reg_offset, &val); @@ -64,15 +73,36 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, }; +static const struct meson_reset_drvdata meson_gxbb_data = { + .reg_count = 8, + .level_offset = 0x7c, +}; + +static const struct meson_reset_drvdata meson_a1_data = { + .reg_count = 3, + .level_offset = 0x40, +}; + static const struct udevice_id meson_reset_ids[] = { - { .compatible = "amlogic,meson-gxbb-reset" }, - { .compatible = "amlogic,meson-axg-reset" }, + { + .compatible = "amlogic,meson-gxbb-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-axg-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-a1-reset", + .data = (ulong)&meson_a1_data, + }, { } }; static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev); + priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev); return regmap_init_mem(dev_ofnode(dev), &priv->regmap); } -- 2.25.1
[PATCH v3 4/8] phy: move clk enable/disable in init/exit
It is better to place clk_enable() in phy_meson_g12a_usb2_init() and clk_disable() in phy_meson_g12a_usb2_exit(). For more detailed information, please see comments in the review of a similar driver in the Linux Kernel: https://lore.kernel.org/all/CAFBinCCEhobbyKHuKDWzTYCQWgNT1-e8=7hmhq1mvt6cueo...@mail.gmail.com/ Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/phy/meson-g12a-usb2.c | 19 --- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index a803b6796c..2ea0498f86 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -161,6 +161,14 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret; +#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { + pr_err("failed to enable PHY clock\n"); + return ret; + } +#endif + ret = reset_assert(&priv->reset); udelay(1); ret |= reset_deassert(&priv->reset); @@ -253,6 +261,10 @@ static int phy_meson_g12a_usb2_exit(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret; +#if CONFIG_IS_ENABLED(CLK) + clk_disable(&priv->clk); +#endif + ret = reset_assert(&priv->reset); if (ret) return ret; @@ -290,13 +302,6 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - - ret = clk_enable(&priv->clk); - if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { - pr_err("failed to enable PHY clock\n"); - clk_free(&priv->clk); - return ret; - } #endif return 0; -- 2.25.1
[PATCH v3 3/8] phy: get rid of raw hex values
It is better to use defines instead of write raw hex values in regmap. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/phy/meson-g12a-usb2.c | 161 -- 1 file changed, 153 insertions(+), 8 deletions(-) diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 8b24322515..a803b6796c 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -24,12 +24,28 @@ #include #include +#include #define PHY_CTRL_R00x0 #define PHY_CTRL_R10x4 #define PHY_CTRL_R20x8 + #define PHY_CTRL_R30xc + #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0) + #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2) + #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4) + #define PHY_CTRL_R40x10 + #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0) + #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8) + #define PHY_CTRL_R4_CALIB_CODE_23_16GENMASK(23, 16) + #define PHY_CTRL_R4_I_C2L_CAL_ENBIT(24) + #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25) + #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26) + #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30) + #define PHY_CTRL_R50x14 #define PHY_CTRL_R60x18 #define PHY_CTRL_R70x1c @@ -38,15 +54,93 @@ #define PHY_CTRL_R10 0x28 #define PHY_CTRL_R11 0x2c #define PHY_CTRL_R12 0x30 + #define PHY_CTRL_R13 0x34 + #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0) + #define PHY_CTRL_R13_LOAD_STAT BIT(14) + #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15) + #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16) + #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23) + #define PHY_CTRL_R13_I_C2L_HS_ENBIT(24) + #define PHY_CTRL_R13_I_C2L_FS_ENBIT(25) + #define PHY_CTRL_R13_I_C2L_LS_ENBIT(26) + #define PHY_CTRL_R13_I_C2L_HS_OEBIT(27) + #define PHY_CTRL_R13_I_C2L_FS_OEBIT(28) + #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29) + #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30) + #define PHY_CTRL_R14 0x38 #define PHY_CTRL_R15 0x3c + #define PHY_CTRL_R16 0x40 + #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0) + #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10) + #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20) + #define PHY_CTRL_R16_MPLL_SDM_ENBIT(21) + #define PHY_CTRL_R16_MPLL_LOAD BIT(22) + #define PHY_CTRL_R16_MPLL_DCO_SDM_ENBIT(23) + #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24) + #define PHY_CTRL_R16_MPLL_LOCK_FBIT(26) + #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27) + #define PHY_CTRL_R16_MPLL_ENBIT(28) + #define PHY_CTRL_R16_MPLL_RESET BIT(29) + #define PHY_CTRL_R16_MPLL_LOCK BIT(30) + #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31) + #define PHY_CTRL_R17 0x44 + #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0) + #define PHY_CTRL_R17_MPLL_FIX_ENBIT(16) + #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17) + #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20) + #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23) + #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24
[PATCH v3 6/8] a1: clk: Add missing USB_PHY_IN and USB_PHY gates
From: Igor Prusov We use this clocks in dwc3 driver. Signed-off-by: Igor Prusov Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/clk/meson/a1.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c index 3aec42f33b..1075ba7333 100644 --- a/drivers/clk/meson/a1.c +++ b/drivers/clk/meson/a1.c @@ -238,6 +238,12 @@ static const struct meson_clk_info *meson_clocks[] = { [CLKID_FIXPLL_IN] = CLK_GATE("fixpll_in", A1_SYS_OSCIN_CTRL, 1, EXTERNAL_XTAL ), + [CLKID_USB_PHY_IN] = CLK_GATE("usb_phy_in", A1_SYS_OSCIN_CTRL, 2, + EXTERNAL_XTAL + ), + [CLKID_USB_PHY] = CLK_GATE("usb_phy", A1_SYS_CLK_EN0, 27, + CLKID_SYS + ), [CLKID_SARADC] = CLK_GATE("saradc", A1_SAR_ADC_CLK_CTR, 8, -ENOENT ), -- 2.25.1
[PATCH v3 5/8] phy: support Amlogic A1 family
Setting G12A and A1 is similar, so we can use G12A phy driver with little changes. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 79 --- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 8ac5769ed9..60138beca4 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -200,7 +200,7 @@ config MESON_GXL_USB_PHY config MESON_G12A_USB_PHY bool "Amlogic Meson G12A USB PHYs" - depends on PHY && ARCH_MESON && MESON_G12A + depends on PHY && ARCH_MESON && (MESON_G12A || MESON_A1) imply REGMAP help This is the generic phy driver for the Amlogic Meson G12A diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 2ea0498f86..4ba3992bda 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -147,18 +148,28 @@ #define RESET_COMPLETE_TIME1000 #define PLL_RESET_COMPLETE_TIME100 +enum meson_soc_id { + MESON_SOC_A1, + MESON_SOC_G12A, +}; + struct phy_meson_g12a_usb2_priv { struct regmap *regmap; #if CONFIG_IS_ENABLED(CLK) struct clk clk; #endif struct reset_ctlreset; +#if CONFIG_IS_ENABLED(POWER_DOMAIN) + struct power_domain pwrdm; +#endif + int soc_id; }; static int phy_meson_g12a_usb2_init(struct phy *phy) { struct udevice *dev = phy->dev; struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); + u32 value; int ret; #if CONFIG_IS_ENABLED(CLK) @@ -197,8 +208,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); - regmap_write(priv->regmap, PHY_CTRL_R18, - FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | + value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | @@ -210,6 +220,11 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | PHY_CTRL_R18_MPLL_ACG_RANGE; + if (priv->soc_id == MESON_SOC_A1) + value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL; + + regmap_write(priv->regmap, PHY_CTRL_R18, value); + udelay(PLL_RESET_COMPLETE_TIME); /* UnReset PLL */ @@ -232,13 +247,19 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); - regmap_write(priv->regmap, PHY_CTRL_R4, - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | - PHY_CTRL_R4_TEST_BYPASS_MODE_EN | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + if (priv->soc_id == MESON_SOC_G12A) + regmap_write(priv->regmap, PHY_CTRL_R4, + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | + PHY_CTRL_R4_TEST_BYPASS_MODE_EN | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + else if (priv->soc_id == MESON_SOC_A1) + regmap_write(priv->regmap, PHY_CTRL_R21, + PHY_CTRL_R21_USB2_CAL_ACK_EN | + PHY_CTRL_R21_USB2_TX_STRG_PD | + FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2)); /* Tuning Disconnect Threshold */ regmap_write(priv->regmap, PHY_CTRL_R3, @@ -247,10 +268,15 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3)); /* Analog Settings */ - regmap_write(priv->regmap, PHY_CTRL_R14, 0); - regmap_write(priv->regmap, PHY_CTRL_R13, - PHY_CTRL_R13_UPDATE_PMA_SIGNALS | - FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + if (priv->soc_id == MESON_SOC_G12A) { + regmap_write(priv->regmap, PHY_CTRL_R14, 0); + regmap_write(priv->regmap, PHY_CTRL_R13, + PHY_CTRL_R13_UPDATE_PMA_SIGNALS | +
[PATCH v3 8/8] ad401: enable USB stack
Currently we have all drivers for use USB stack on A1-series SoC's. Let's enable USB options for the Amlogic AD401 reference A1 SoC board. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- configs/ad401_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configs/ad401_defconfig b/configs/ad401_defconfig index 31752cc7f5..b9aca3ab0d 100644 --- a/configs/ad401_defconfig +++ b/configs/ad401_defconfig @@ -51,4 +51,7 @@ CONFIG_DEBUG_UART_SKIP_INIT=y CONFIG_MESON_SERIAL=y CONFIG_SPI=y CONFIG_DM_SPI=y +CONFIG_USB=y +CONFIG_DM_USB_GADGET=y +CONFIG_USB_GADGET=y CONFIG_WDT=y -- 2.25.1
[PATCH v3 7/8] dwc3: add support for Amlogic A1 family
Now the driver supports also A1 phy layer. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- drivers/usb/dwc3/dwc3-meson-g12a.c | 79 ++ 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index dc5a976f71..e0356e653f 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -29,6 +29,7 @@ #include #include #include +#include /* USB2 Ports Control Registers */ @@ -103,10 +104,22 @@ enum { PHY_COUNT, }; -static const char *phy_names[PHY_COUNT] = { +static const char *const dwc3_meson_g12a_phy_names[] = { "usb2-phy0", "usb2-phy1", "usb3-phy0", }; +static const char *const dwc3_meson_a1_phy_names[] = { + "usb2-phy0", "usb2-phy1" +}; + +struct dwc3_meson_g12a; + +struct dwc3_meson_g12a_drvdata { + const char *const *phy_names; + unsigned int phy_cnt; + int (*clk_init)(struct dwc3_meson_g12a *priv); +}; + struct dwc3_meson_g12a { struct udevice *dev; struct regmap *regmap; @@ -120,6 +133,7 @@ struct dwc3_meson_g12a { #if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vbus_supply; #endif + struct dwc3_meson_g12a_drvdata *drvdata; }; #define U2P_REG_SIZE 0x20 @@ -294,10 +308,11 @@ int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode) static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) { + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i, ret; - for (i = 0 ; i < PHY_COUNT ; ++i) { - ret = generic_phy_get_by_name(priv->dev, phy_names[i], + for (i = 0 ; i < data->phy_cnt; ++i) { + ret = generic_phy_get_by_name(priv->dev, data->phy_names[i], &priv->phys[i]); if (ret == -ENOENT || ret == -ENODATA) continue; @@ -355,18 +370,36 @@ static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv) return 0; } +static int dwc3_meson_a1_clk_init(struct dwc3_meson_g12a *priv) +{ + int ret; + + ret = clk_get_by_name(priv->dev, "usb_bus", &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + return 0; +} + static int dwc3_meson_g12a_probe(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = + (struct dwc3_meson_g12a_drvdata *)dev_get_driver_data(dev); int ret, i; + priv->drvdata = data; priv->dev = dev; ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret; - ret = dwc3_meson_g12a_clk_init(priv); + ret = data->clk_init(priv); if (ret) return ret; @@ -399,7 +432,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) if (ret) return ret; - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -408,7 +441,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) goto err_phy_init; } - for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -420,7 +453,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) return 0; err_phy_init: - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt ; ++i) { if (!priv->phys[i].dev) continue; @@ -433,20 +466,21 @@ err_phy_init: static int dwc3_meson_g12a_remove(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i; reset_release_all(&priv->reset, 1); clk_release_all(&priv->clk, 1); - for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; generic_phy_power_off(&priv->phys[i]); } - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue; @@ -456,11 +490,26 @@ static int dwc3_meson_g12a_remove(struct udevice *dev) return dm_scan_fdt_dev(dev); } +static const struct dwc3_meson_g12a_drvdata meson_g12a_drvdata =
[PATCH v2 1/2] meson-a1: dts: add hw rng node
Add support for hardware random number generator of Amlogic Meson SoCs. Signed-off-by: Alexey Romanov --- arch/arm/dts/meson-a1.dtsi | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/dts/meson-a1.dtsi b/arch/arm/dts/meson-a1.dtsi index 6509329b85..e6e72d4004 100644 --- a/arch/arm/dts/meson-a1.dtsi +++ b/arch/arm/dts/meson-a1.dtsi @@ -124,6 +124,11 @@ clock-names = "xtal", "pclk", "baud"; status = "disabled"; }; + + hwrng: rng@5118 { + compatible = "amlogic,meson-rng"; + reg = <0x0 0x5118 0x0 0x4>; + }; }; gic: interrupt-controller@ff901000 { -- 2.25.1
[PATCH v2 2/2] meson-a1: dts: add ao secure node
ao-secure node can be used to get information about the board, so, for example, using show_board_info() we can get following information for board with Meson A1 SoC: SoC: Amlogic Meson A1 (A113L) Revision 2c:a (1:a) Signed-off-by: Alexey Romanov --- arch/arm/dts/meson-a1.dtsi | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/dts/meson-a1.dtsi b/arch/arm/dts/meson-a1.dtsi index e6e72d4004..e3a42c5b24 100644 --- a/arch/arm/dts/meson-a1.dtsi +++ b/arch/arm/dts/meson-a1.dtsi @@ -129,6 +129,12 @@ compatible = "amlogic,meson-rng"; reg = <0x0 0x5118 0x0 0x4>; }; + + sec_AO: ao-secure@5a20 { + compatible = "amlogic,meson-gx-ao-secure", "syscon"; + reg = <0x0 0x5a20 0x0 0x140>; + amlogic,has-chip-id; + }; }; gic: interrupt-controller@ff901000 { -- 2.25.1
[PATCH v2 0/2] Meson A1: add HW RNG and AO Secure nodes
Hello! This patchest adds HW RNG and AO Secure definition in device tree for Amlogic A1-series. V2: - Rebased over latest amlogic U-Boot branch. Alexey Romanov (2): meson-a1: dts: add hw rng node meson-a1: dts: add ao secure node arch/arm/dts/meson-a1.dtsi | 11 +++ 1 file changed, 11 insertions(+) -- 2.25.1
[PATCH v2 0/1] hwrng: meson - add support for S4
Hello! This patch adds support for Meson S4 series hardware number generator using new algo. V2: - Sync with Linux version. Alexey Romanov (1): drivers: rng: add support for Meson S4 drivers/rng/meson-rng.c | 72 - 1 file changed, 71 insertions(+), 1 deletion(-) -- 2.25.1
[PATCH v2 1/1] drivers: rng: add support for Meson S4
For some Amlogic SOC's, mechanism to obtain random number has been changed. For example, S4 now uses status bit waiting algo. Signed-off-by: Alexey Romanov --- drivers/rng/meson-rng.c | 72 - 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/rng/meson-rng.c b/drivers/rng/meson-rng.c index e0a1e8c7e0..ba60325b94 100644 --- a/drivers/rng/meson-rng.c +++ b/drivers/rng/meson-rng.c @@ -10,10 +10,23 @@ #include #include #include +#include + +#define RNG_DATA 0x00 +#define RNG_S4_DATA0x08 +#define RNG_S4_CFG 0x00 + +#define RUN_BITBIT(0) +#define SEED_READY_STS_BIT BIT(31) + +struct meson_rng_priv { + u32 (*read)(fdt_addr_t base); +}; struct meson_rng_plat { fdt_addr_t base; struct clk clk; + struct meson_rng_priv *priv; }; /** @@ -27,10 +40,11 @@ struct meson_rng_plat { static int meson_rng_read(struct udevice *dev, void *data, size_t len) { struct meson_rng_plat *pdata = dev_get_plat(dev); + struct meson_rng_priv *priv = pdata->priv; char *buffer = (char *)data; while (len) { - u32 rand = readl(pdata->base); + u32 rand = priv->read(pdata->base); size_t step; if (len >= 4) @@ -44,6 +58,47 @@ static int meson_rng_read(struct udevice *dev, void *data, size_t len) return 0; } +static int meson_rng_wait_status(void __iomem *cfg_addr, int bit) +{ + u32 status = 0; + int ret; + + ret = readl_relaxed_poll_timeout(cfg_addr, +status, !(status & bit), +1); + if (ret) + return -EBUSY; + + return 0; +} + +static u32 meson_common_rng_read(fdt_addr_t base) +{ + return readl(base); +} + +static u32 meson_s4_rng_read(fdt_addr_t base) +{ + void __iomem *cfg_addr = (void *)base + RNG_S4_CFG; + int err; + + writel_relaxed(readl_relaxed(cfg_addr) | SEED_READY_STS_BIT, cfg_addr); + + err = meson_rng_wait_status(cfg_addr, SEED_READY_STS_BIT); + if (err) { + pr_err("Seed isn't ready, try again\n"); + return err; + } + + err = meson_rng_wait_status(cfg_addr, RUN_BIT); + if (err) { + pr_err("Can't get random number, try again\n"); + return err; + } + + return readl_relaxed(base + RNG_S4_DATA); +} + /** * meson_rng_probe() - probe rng device * @@ -59,6 +114,8 @@ static int meson_rng_probe(struct udevice *dev) if (err) return err; + pdata->priv = dev_get_driver_data(dev); + return 0; } @@ -102,9 +159,22 @@ static const struct dm_rng_ops meson_rng_ops = { .read = meson_rng_read, }; +static const struct meson_rng_priv meson_rng_priv = { + .read = meson_common_rng_read, +}; + +static const struct meson_rng_priv meson_rng_priv_s4 = { + .read = meson_s4_rng_read, +}; + static const struct udevice_id meson_rng_match[] = { { .compatible = "amlogic,meson-rng", + .data = (ulong)&meson_rng_priv, + }, + { + .compatible = "amlogic,meson-s4-rng", + .data = (ulong)&meson_rng_priv_s4, }, {}, }; -- 2.25.1
[PATCH v1 0/3] Meson Secure PWRC Driver
Hello! This patch set adds support (driver and sm functions) for working with power domain controller using secure monitor for Amlogic A1-series. Additionally, in the future, the driver can be used for other Amlgoic SoC series, such as S4. Alexey Romanov (3): arch/arm: meson: sm: introduce power domain functions drivers: meson: introduce secure power controller driver arch/arm64: meson-a1: dts: move pwrc node to bus arch/arm/dts/meson-a1.dtsi | 12 +- arch/arm/include/asm/arch-meson/sm.h | 30 arch/arm/mach-meson/sm.c | 14 ++ drivers/power/domain/Kconfig | 7 + drivers/power/domain/Makefile | 1 + drivers/power/domain/meson-secure-pwrc.c | 160 + include/dt-bindings/power/meson-a1-power.h | 32 + 7 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 drivers/power/domain/meson-secure-pwrc.c create mode 100644 include/dt-bindings/power/meson-a1-power.h -- 2.38.1
[PATCH v1 1/3] arch/arm: meson: sm: introduce power domain functions
This commit adds functions to manage secure power domain for Amlogic SoC's using smc functionality. Signed-off-by: Alexey Romanov --- arch/arm/include/asm/arch-meson/sm.h | 30 arch/arm/mach-meson/sm.c | 14 + 2 files changed, 44 insertions(+) diff --git a/arch/arm/include/asm/arch-meson/sm.h b/arch/arm/include/asm/arch-meson/sm.h index 53b75176493..4b1d564bc48 100644 --- a/arch/arm/include/asm/arch-meson/sm.h +++ b/arch/arm/include/asm/arch-meson/sm.h @@ -58,4 +58,34 @@ enum { */ int meson_sm_get_reboot_reason(void); +#define PWRDM_OFF 0 +#define PWRDM_ON 1 + +/** + * meson_sm_pwrdm_set - do command at specified power domain. + * + * @index: power domain index. + * @cmd: command index. + * @return: zero on success or error code on failure. + */ +int meson_sm_pwrdm_set(size_t index, int cmd); + +/** + * meson_sm_pwrdm_off - disable specified power domain. + * + * @index: power domain index. + * @return: zero on success or error code on failure. + */ +#define meson_sm_pwrdm_off(index) \ + meson_sm_pwrdm_set(index, PWRDM_OFF) + +/** + * meson_sm_pwrdm_on - enable specified power domain. + * + * @index: power domain index. + * @return: zero on success or error code on failure. + */ +#define meson_sm_pwrdm_on(index) \ + meson_sm_pwrdm_set(index, PWRDM_ON) + #endif /* __MESON_SM_H__ */ diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index f2ca7e76932..d600c64d0be 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -24,6 +24,7 @@ #define FN_EFUSE_READ 0x8230 #define FN_EFUSE_WRITE 0x8231 #define FN_CHIP_ID 0x8244 +#define FN_PWRDM_SET 0x8293 static void *shmem_input; static void *shmem_output; @@ -137,3 +138,16 @@ int meson_sm_get_reboot_reason(void) /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */ return FIELD_GET(REBOOT_REASON_MASK, reason); } + +int meson_sm_pwrdm_set(size_t index, int cmd) +{ + struct pt_regs regs; + + regs.regs[0] = FN_PWRDM_SET; + regs.regs[1] = index; + regs.regs[2] = cmd; + + smc_call(®s); + + return regs.regs[0]; +} -- 2.38.1
[PATCH v1 2/3] drivers: meson: introduce secure power controller driver
This patch adds Power controller driver support for Amlogic A1 family using secure monitor calls. The power domains register only can access in secure world. Signed-off-by: Alexey Romanov --- drivers/power/domain/Kconfig | 7 + drivers/power/domain/Makefile | 1 + drivers/power/domain/meson-secure-pwrc.c | 160 + include/dt-bindings/power/meson-a1-power.h | 32 + 4 files changed, 200 insertions(+) create mode 100644 drivers/power/domain/meson-secure-pwrc.c create mode 100644 include/dt-bindings/power/meson-a1-power.h diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 7e1b8c072fa..411c210756a 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -68,6 +68,13 @@ config MESON_EE_POWER_DOMAIN Enable support for manipulating Amlogic Meson Everything-Else power domains. +config MESON_SECURE_POWER_DOMAIN + bool "Enable Amlogic Secure power domain driver" + depends on POWER_DOMAIN && ARCH_MESON && MESON_A1 + help + Enable support for manipulating Amlogic Meson Secure power domains. + Support for Amlogic A1 series. + 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 e6244776216..aa5a4ba57cd 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_IMX8MP_HSIOMIX_BLKCTRL) += imx8mp-hsiomix.o 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_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o diff --git a/drivers/power/domain/meson-secure-pwrc.c b/drivers/power/domain/meson-secure-pwrc.c new file mode 100644 index 000..f70f8e02423 --- /dev/null +++ b/drivers/power/domain/meson-secure-pwrc.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include + +struct meson_secure_pwrc_domain_desc { + char *name; + size_t index; +}; + +struct meson_secure_pwrc_domain_data { + unsigned int count; + struct meson_secure_pwrc_domain_desc *domains; +}; + +struct meson_secure_pwrc_priv { + const struct meson_secure_pwrc_domain_data *data; +}; + +static int meson_secure_pwrc_on(struct power_domain *power_domain) +{ + struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev); + struct meson_secure_pwrc_domain_desc *pwrc_domain; + int err; + + pwrc_domain = &priv->data->domains[power_domain->id]; + + err = meson_sm_pwrdm_on(pwrc_domain->index); + if (err) { + pr_err("meson_sm_pwrdm_on() failed (%d)\n", err); + return err; + } + + pr_debug("enable %s power domain\n", pwrc_domain->name); + + return 0; +} + +static int meson_secure_pwrc_off(struct power_domain *power_domain) +{ + struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev); + struct meson_secure_pwrc_domain_desc *pwrc_domain; + int err; + + pwrc_domain = &priv->data->domains[power_domain->id]; + + err = meson_sm_pwrdm_off(pwrc_domain->index); + if (err) { + pr_err("meson_sm_pwrdm_off() failed (%d)\n", err); + return err; + } + + pr_debug("disable %s power domain\n", pwrc_domain->name); + + return 0; +} + +static int meson_secure_pwrc_of_xlate(struct power_domain *power_domain, + struct ofnode_phandle_args *args) +{ + struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev); + struct meson_secure_pwrc_domain_desc *pwrc_domain; + + if (args->args_count < 1) { + pr_err("invalid args count: %d\n", args->args_count); + return -EINVAL; + } + + power_domain->id = args->args[0]; + + if (power_domain->id >= priv->data->count) { + pr_err("domain with ID=%lu is invalid\n", power_domain->id); + return -EINVAL; + } + + pwrc_domain = &priv->data->domains[power_domain->id]; + + if (!pwrc_domain->name) { + pr_err("domain with ID=%lu is invalid\n", power_domain->id); + return -EINVAL; + } + + return 0; +} + +#define SEC_PD(__n
[PATCH v1 3/3] arch/arm64: meson-a1: dts: move pwrc node to bus
This is necessary so that pwrc can be used together with peripherals when described in a bus node. For example, in the future, this will be USB. Signed-off-by: Alexey Romanov --- arch/arm/dts/meson-a1.dtsi | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/dts/meson-a1.dtsi b/arch/arm/dts/meson-a1.dtsi index 9776b2d8798..f3560cbc3a4 100644 --- a/arch/arm/dts/meson-a1.dtsi +++ b/arch/arm/dts/meson-a1.dtsi @@ -65,12 +65,6 @@ sm: secure-monitor { compatible = "amlogic,meson-gxbb-sm"; - - pwrc: power-controller { - compatible = "amlogic,meson-a1-pwrc"; - #power-domain-cells = <1>; - status = "okay"; - }; }; soc { @@ -161,6 +155,12 @@ #address-cells = <0>; }; + pwrc: power-controller { + compatible = "amlogic,meson-a1-pwrc"; + #power-domain-cells = <1>; + status = "okay"; + }; + usb: usb@fe004400 { compatible = "amlogic,meson-a1-usb-ctrl"; reg = <0x0 0xfe004400 0x0 0xa0>; -- 2.38.1
Re: [PATCH v1 1/2] drivers: firmware: introduce Meson Secure Monitor driver
Hi Neil, I would like to know your opinion before I change the patches. On Sat, Jul 15, 2023 at 05:40:53PM -0600, Simon Glass wrote: > Hi, > > On Thu, 13 Jul 2023 at 23:30, AKASHI Takahiro > wrote: > > > > On Tue, Jul 11, 2023 at 01:13:29PM -0600, Simon Glass wrote: > > > +AKASHI Takahiro > > > > Me? > > Yes, I'm asking for your help to try to clean this stuff up. > > > > > > Hi Alexey, > > > > > > On Tue, 11 Jul 2023 at 04:25, Alexey Romanov > > > wrote: > > > > > > > > Hi Simon, > > > > > > > > On Mon, Jul 10, 2023 at 01:45:53PM -0600, Simon Glass wrote: > > > > > Hi Alexey, > > > > > > > > > > On Mon, 10 Jul 2023 at 02:34, Alexey Romanov > > > > > wrote: > > > > > > > > > > > > > > > > > > Hello! > > > > > > > > > > > > On Fri, Jul 07, 2023 at 11:35:47AM -0600, Simon Glass wrote: > > > > > > > Hi Alexey, > > > > > > > > > > > > > > On Fri, 7 Jul 2023 at 09:43, Alexey Romanov > > > > > > > wrote: > > > > > > > > > > > > > > > > Hello, Simon! > > > > > > > > > > > > > > > > On Thu, Jul 06, 2023 at 09:58:02AM -0600, Simon Glass wrote: > > > > > > > > > Hi Alexey, > > > > > > > > > > > > > > > > > > On Thu, 6 Jul 2023 at 14:16, Alexey Romanov > > > > > > > > > wrote: > > > > > > > > > > > > > > > > > > > > At the moment, only smc API is a set of functions in > > > > > > > > > > arch/arm/mach-meson/sm.c. This approach is hard to configure > > > > > > > > > > and also doesni't contain any generic API for calling smc. > > > > > > > > > > > > > > > > > > > > This patch add Meson SM driver with generic API (struct > > > > > > > > > > meson_sm_ops): > > > > > > > > > > > > > > > > > > > > - sm_call() > > > > > > > > > > - sm_call_write() > > > > > > > > > > - sm_call_read() > > > > > > > > > > > > > > > > > > > > A typical driver usage example is shown here: > > > > > > > > > > > > > > > > > > > > 1. uclass_get_device_by_driver(UCLASS_FIRMWARE, > > > > > > > > > > "secure-monitor", &dev); > > > > > > > > > > 2. handle = meson_sm_get_handle(dev); > > > > > > > > > > 3. handle->ops.sm_call(dev, cmd, ...); > > > > > > > > > > > > > > > > > > > > Signed-off-by: Alexey Romanov > > > > > > > > > > --- > > > > > > > > > > arch/arm/mach-meson/Kconfig | 1 + > > > > > > > > > > drivers/firmware/Kconfig | 10 ++ > > > > > > > > > > drivers/firmware/Makefile | 1 + > > > > > > > > > > drivers/firmware/meson/Kconfig| 6 + > > > > > > > > > > drivers/firmware/meson/Makefile | 3 + > > > > > > > > > > drivers/firmware/meson/meson_sm.c | 217 > > > > > > > > > > ++ > > > > > > > > > > include/meson/sm_handle.h | 38 ++ > > > > > > > > > > 7 files changed, 276 insertions(+) > > > > > > > > > > create mode 100644 drivers/firmware/meson/Kconfig > > > > > > > > > > create mode 100644 drivers/firmware/meson/Makefile > > > > > > > > > > create mode 100644 drivers/firmware/meson/meson_sm.c > > > > > > > > > > create mode 100644 include/meson/sm_handle.h > > > > > > > > > > > > > > > > > > Please can you use the remoteproc uclass for this and add a > > > > > > > > > proper driver? > > > > > > > > > > > > > > > > > > > > > > > > > I don't see it architectural
Re: [PATCH v1] arch/arm: sm: introduce efusedump command
Hello! On Mon, Dec 12, 2022 at 11:08:34AM -0500, Tom Rini wrote: > On Fri, Dec 09, 2022 at 03:52:04PM +0300, Alexey Romanov wrote: > > > Using this command user can print efuse memory: > > > > $ sm efusedump 0 10 > > : ff 00 31 00 00 ff 66 00 00 00 ..1...f... > > > > Signed-off-by: Alexey Romanov > > --- > > arch/arm/mach-meson/sm.c | 36 +++- > > 1 file changed, 35 insertions(+), 1 deletion(-) > > This needs to be moved done under cmd/ somewhere, perhaps cmd/meson/ > > -- > Tom Do you mean it must be moved by a different patchset? From my point of view, your comment is totally right, because arch dependent commands are located at cmd/ARCH path. But I'm afraid my patchset is just about new helper command. Anyway, I can send a new different patchset with refactoring suggested by you. But, please, comment out some words about new efuse command if possible. -- Thank you, Alexey
[PATCH v2 0/3] arch-meson: introduce efusedump command
Keeping the commands code in an arch/ is not correct. This patchset moves the meson smc commands from arch/arm/mach-meson to cmd/meson folder and also adds a new 'efusedump' command with which user can print efuse memory. Alexey Romanov (3): asm/arch-meson: add missing meson_sm_write_efuse signature arm/mach-meson: move smc commands in cmd/meson cmd/arm: meson: sm: introduce efusedump command MAINTAINERS | 1 + arch/arm/include/asm/arch-meson/sm.h | 2 + arch/arm/mach-meson/sm.c | 144 - cmd/Kconfig | 7 + cmd/Makefile | 3 + cmd/meson/Makefile | 5 + cmd/meson/sm.c | 187 +++ 7 files changed, 205 insertions(+), 144 deletions(-) create mode 100644 cmd/meson/Makefile create mode 100644 cmd/meson/sm.c -- 2.25.1
[PATCH v2 1/3] asm/arch-meson: add missing meson_sm_write_efuse signature
This function can be used by other modules. Signed-off-by: Alexey Romanov --- arch/arm/include/asm/arch-meson/sm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/include/asm/arch-meson/sm.h b/arch/arm/include/asm/arch-meson/sm.h index f3ae46a6d6b..b68edf842e4 100644 --- a/arch/arm/include/asm/arch-meson/sm.h +++ b/arch/arm/include/asm/arch-meson/sm.h @@ -8,6 +8,8 @@ ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size); +ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size); + #define SM_SERIAL_SIZE 12 int meson_sm_get_serial(void *buffer, size_t size); -- 2.25.1
[PATCH v2 3/3] cmd/arm: meson: sm: introduce efusedump command
Using this command user can print efuse memory: $ sm efusedump 0 10 : ff 00 31 00 00 ff 66 00 00 00 ..1...f... Signed-off-by: Alexey Romanov --- cmd/meson/sm.c | 35 ++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/cmd/meson/sm.c b/cmd/meson/sm.c index 1a3a2c7920a..9493f4fd846 100644 --- a/cmd/meson/sm.c +++ b/cmd/meson/sm.c @@ -117,11 +117,43 @@ static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_SUCCESS; } +static int do_efuse_dump(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong offset, size; + u8 *buffer; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + offset = simple_strtoul(argv[1], NULL, 0); + size = simple_strtoul(argv[2], NULL, 0); + buffer = malloc(size); + if (!buffer) { + pr_err("Failed to allocate %lu bytes\n", size); + return CMD_RET_FAILURE; + } + + ret = meson_sm_read_efuse(offset, (void *)buffer, size); + if (ret != size) { + ret = CMD_RET_FAILURE; + goto free_buffer; + } + + print_buffer(0, buffer, 1, size, 0); + +free_buffer: + free(buffer); + return ret; +} + static struct cmd_tbl cmd_sm_sub[] = { U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""), U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", ""), + U_BOOT_CMD_MKENT(efusedump, 3, 1, do_efuse_dump, "", ""), }; static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc, @@ -150,5 +182,6 @@ U_BOOT_CMD( "serial - read chip unique id to memory address\n" "sm reboot_reason [name] - get reboot reason and store to environment\n" "sm efuseread- read efuse to memory address\n" - "sm efusewrite- write into efuse from memory address" + "sm efusewrite- write into efuse from memory address\n" + "sm efusedump - dump efuse data range to console" ); -- 2.25.1
[PATCH v2 2/3] arm/mach-meson: move smc commands in cmd/meson
It is incorrect to keep commands in the arch/ folder. Signed-off-by: Alexey Romanov --- MAINTAINERS | 1 + arch/arm/mach-meson/sm.c | 144 cmd/Kconfig | 7 ++ cmd/Makefile | 3 + cmd/meson/Makefile | 5 ++ cmd/meson/sm.c | 154 +++ 6 files changed, 170 insertions(+), 144 deletions(-) create mode 100644 cmd/meson/Makefile create mode 100644 cmd/meson/sm.c diff --git a/MAINTAINERS b/MAINTAINERS index 7f27ff4c20f..7a5460d4922 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -149,6 +149,7 @@ L: u-boot-amlo...@groups.io T: git https://source.denx.de/u-boot/custodians/u-boot-amlogic.git F: arch/arm/mach-meson/ F: arch/arm/include/asm/arch-meson/ +F: cmd/meson/ F: drivers/clk/meson/ F: drivers/serial/serial_meson.c F: drivers/reset/reset-meson.c diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index d6eb910689f..f2ca7e76932 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -139,145 +137,3 @@ int meson_sm_get_reboot_reason(void) /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */ return FIELD_GET(REBOOT_REASON_MASK, reason); } - -static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address; - int ret; - - if (argc < 2) - return CMD_RET_USAGE; - - address = simple_strtoul(argv[1], NULL, 0); - - ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE); - if (ret) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -#define MAX_REBOOT_REASONS 14 - -static const char *reboot_reasons[MAX_REBOOT_REASONS] = { - [REBOOT_REASON_COLD] = "cold_boot", - [REBOOT_REASON_NORMAL] = "normal", - [REBOOT_REASON_RECOVERY] = "recovery", - [REBOOT_REASON_UPDATE] = "update", - [REBOOT_REASON_FASTBOOT] = "fastboot", - [REBOOT_REASON_SUSPEND_OFF] = "suspend_off", - [REBOOT_REASON_HIBERNATE] = "hibernate", - [REBOOT_REASON_BOOTLOADER] = "bootloader", - [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot", - [REBOOT_REASON_RPMBP] = "rpmbp", - [REBOOT_REASON_CRASH_DUMP] = "crash_dump", - [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic", - [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot", -}; - -static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - const char *reason_str; - char *destarg = NULL; - int reason; - - if (argc > 1) - destarg = argv[1]; - - reason = meson_sm_get_reboot_reason(); - if (reason < 0) - return CMD_RET_FAILURE; - - if (reason >= MAX_REBOOT_REASONS || - !reboot_reasons[reason]) - reason_str = "unknown"; - else - reason_str = reboot_reasons[reason]; - - if (destarg) - env_set(destarg, reason_str); - else - printf("reboot reason: %s (%x)\n", reason_str, reason); - - return CMD_RET_SUCCESS; -} - -static int do_efuse_read(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address, offset, size; - int ret; - - if (argc < 4) - return CMD_RET_USAGE; - -offset = simple_strtoul(argv[1], NULL, 0); -size = simple_strtoul(argv[2], NULL, 0); - -address = simple_strtoul(argv[3], NULL, 0); - - ret = meson_sm_read_efuse(offset, (void *)address, size); - if (ret != size) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address, offset, size; - int ret; - - if (argc < 4) - return CMD_RET_USAGE; - -offset = simple_strtoul(argv[1], NULL, 0); -size = simple_strtoul(argv[2], NULL, 0); - -address = simple_strtoul(argv[3], NULL, 0); - - ret = meson_sm_write_efuse(offset, (void *)address, size); - if (ret != size) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -static struct cmd_tbl cmd_sm_sub[] = { - U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), - U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), - U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""), - U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", "
Re: [PATCH v2 2/3] arm/mach-meson: move smc commands in cmd/meson
On Wed, Dec 14, 2022 at 11:33:35AM +0100, Mattijs Korpershoek wrote: > On Tue, Dec 13, 2022 at 21:31, Alexey Romanov > wrote: > > > It is incorrect to keep commands in the arch/ folder. > > > > Signed-off-by: Alexey Romanov > > --- > > MAINTAINERS | 1 + > > arch/arm/mach-meson/sm.c | 144 > > cmd/Kconfig | 7 ++ > > cmd/Makefile | 3 + > > cmd/meson/Makefile | 5 ++ > > cmd/meson/sm.c | 154 +++ > > 6 files changed, 170 insertions(+), 144 deletions(-) > > create mode 100644 cmd/meson/Makefile > > create mode 100644 cmd/meson/sm.c > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 7f27ff4c20f..7a5460d4922 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -149,6 +149,7 @@ L: u-boot-amlo...@groups.io > > T: git https://source.denx.de/u-boot/custodians/u-boot-amlogic.git > > F: arch/arm/mach-meson/ > > F: arch/arm/include/asm/arch-meson/ > > +F: cmd/meson/ > > F: drivers/clk/meson/ > > F: drivers/serial/serial_meson.c > > F: drivers/reset/reset-meson.c > > diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c > > index d6eb910689f..f2ca7e76932 100644 > > --- a/arch/arm/mach-meson/sm.c > > +++ b/arch/arm/mach-meson/sm.c > > @@ -6,8 +6,6 @@ > > */ > > > > #include > > -#include > > -#include > > #include > > #include > > #include > > @@ -139,145 +137,3 @@ int meson_sm_get_reboot_reason(void) > > /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */ > > return FIELD_GET(REBOOT_REASON_MASK, reason); > > } > > - > > -static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc, > > - char *const argv[]) > > -{ > > - ulong address; > > - int ret; > > - > > - if (argc < 2) > > - return CMD_RET_USAGE; > > - > > - address = simple_strtoul(argv[1], NULL, 0); > > - > > - ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE); > > - if (ret) > > - return CMD_RET_FAILURE; > > - > > - return CMD_RET_SUCCESS; > > -} > > - > > -#define MAX_REBOOT_REASONS 14 > > - > > -static const char *reboot_reasons[MAX_REBOOT_REASONS] = { > > - [REBOOT_REASON_COLD] = "cold_boot", > > - [REBOOT_REASON_NORMAL] = "normal", > > - [REBOOT_REASON_RECOVERY] = "recovery", > > - [REBOOT_REASON_UPDATE] = "update", > > - [REBOOT_REASON_FASTBOOT] = "fastboot", > > - [REBOOT_REASON_SUSPEND_OFF] = "suspend_off", > > - [REBOOT_REASON_HIBERNATE] = "hibernate", > > - [REBOOT_REASON_BOOTLOADER] = "bootloader", > > - [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot", > > - [REBOOT_REASON_RPMBP] = "rpmbp", > > - [REBOOT_REASON_CRASH_DUMP] = "crash_dump", > > - [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic", > > - [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot", > > -}; > > - > > -static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc, > > - char *const argv[]) > > -{ > > - const char *reason_str; > > - char *destarg = NULL; > > - int reason; > > - > > - if (argc > 1) > > - destarg = argv[1]; > > - > > - reason = meson_sm_get_reboot_reason(); > > - if (reason < 0) > > - return CMD_RET_FAILURE; > > - > > - if (reason >= MAX_REBOOT_REASONS || > > - !reboot_reasons[reason]) > > - reason_str = "unknown"; > > - else > > - reason_str = reboot_reasons[reason]; > > - > > - if (destarg) > > - env_set(destarg, reason_str); > > - else > > - printf("reboot reason: %s (%x)\n", reason_str, reason); > > - > > - return CMD_RET_SUCCESS; > > -} > > - > > -static int do_efuse_read(struct cmd_tbl *cmdtp, int flag, int argc, > > - char *const argv[]) > > -{ > > - ulong address, offset, size; > > - int ret; > > - > > - if (argc < 4) > > - return CMD_RET_USAGE; > > - > > -offset = simple_strtoul(argv[1], NULL, 0); > > -size = simple_strtoul(argv[2], NULL, 0); > > - > > -address = simple_strtoul(argv[3], NULL,
Re: [PATCH v2 1/3] asm/arch-meson: add missing meson_sm_write_efuse signature
Hello! On Tue, Dec 13, 2022 at 08:39:46PM -0800, Simon Glass wrote: > Hi Alexey, > > On Tue, 13 Dec 2022 at 10:32, Alexey Romanov wrote: > > > > This function can be used by other modules. > > > > Signed-off-by: Alexey Romanov > > --- > > arch/arm/include/asm/arch-meson/sm.h | 2 ++ > > 1 file changed, 2 insertions(+) > > > > diff --git a/arch/arm/include/asm/arch-meson/sm.h > > b/arch/arm/include/asm/arch-meson/sm.h > > index f3ae46a6d6b..b68edf842e4 100644 > > --- a/arch/arm/include/asm/arch-meson/sm.h > > +++ b/arch/arm/include/asm/arch-meson/sm.h > > @@ -8,6 +8,8 @@ > > > > ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size); > > > > +ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size); > > + > > #define SM_SERIAL_SIZE 12 > > > > int meson_sm_get_serial(void *buffer, size_t size); > > -- > > 2.25.1 > > > > Should add function comments. > > Also, you might consider adding a uclass for this. It seems like an > important use case that is not handled right now. > > Regards, > Simon I'm afraid we can't generalize sm API for each arch types. It's very close to Secure Monitor vendor implementation and can provide various APIs for different purposes. -- Thank you, Alexey
Re: [PATCH v2 0/3] arch-meson: introduce efusedump command
Hello! On Tue, Dec 13, 2022 at 08:39:43PM -0800, Simon Glass wrote: > Hi Alexey, > > On Tue, 13 Dec 2022 at 10:31, Alexey Romanov wrote: > > > > Keeping the commands code in an arch/ is not correct. This patchset > > moves the meson smc commands from arch/arm/mach-meson to cmd/meson > > folder and also adds a new 'efusedump' command with which user can > > print efuse memory. > > > > Alexey Romanov (3): > > asm/arch-meson: add missing meson_sm_write_efuse signature > > arm/mach-meson: move smc commands in cmd/meson > > cmd/arm: meson: sm: introduce efusedump command > > > > MAINTAINERS | 1 + > > arch/arm/include/asm/arch-meson/sm.h | 2 + > > arch/arm/mach-meson/sm.c | 144 - > > cmd/Kconfig | 7 + > > cmd/Makefile | 3 + > > cmd/meson/Makefile | 5 + > > cmd/meson/sm.c | 187 +++ > > 7 files changed, 205 insertions(+), 144 deletions(-) > > create mode 100644 cmd/meson/Makefile > > create mode 100644 cmd/meson/sm.c > > > > -- > > 2.25.1 > > > > It might be a good time to add some documentation in doc/usage/cmd/meson ? > > Regards, > Simon Yeah, I'll add docs in v3 patchest. -- Thank you, Alexey
[PATCH v3 0/5] arch-meson: introduce efusedump command
Keeping the commands code in an arch/ is not correct. This patchset moves the meson smc commands from arch/arm/mach-meson to cmd/meson folder and also adds a new 'efusedump' command with which user can print efuse memory. Alexey Romanov (5): asm/arch-meson: add missing meson_sm_write_efuse signature arm/mach-meson: move smc commands in cmd/meson doc/usage: cmd: documentation for meson/sm command cmd/arm: meson: sm: introduce efusedump command doc/usage: cmd: sm: documentation efusedump cmd MAINTAINERS | 1 + arch/arm/include/asm/arch-meson/sm.h | 28 arch/arm/mach-meson/sm.c | 144 cmd/Kconfig | 7 + cmd/Makefile | 3 + cmd/meson/Makefile | 5 + cmd/meson/sm.c | 190 +++ doc/usage/cmd/sm.rst | 48 +++ 8 files changed, 282 insertions(+), 144 deletions(-) create mode 100644 cmd/meson/Makefile create mode 100644 cmd/meson/sm.c create mode 100644 doc/usage/cmd/sm.rst -- 2.25.1
[PATCH v3 1/5] asm/arch-meson: add missing meson_sm_write_efuse signature
This function can be used by other modules. Also add comments. Signed-off-by: Alexey Romanov --- arch/arm/include/asm/arch-meson/sm.h | 28 1 file changed, 28 insertions(+) diff --git a/arch/arm/include/asm/arch-meson/sm.h b/arch/arm/include/asm/arch-meson/sm.h index f3ae46a6d6b..53b75176493 100644 --- a/arch/arm/include/asm/arch-meson/sm.h +++ b/arch/arm/include/asm/arch-meson/sm.h @@ -6,10 +6,35 @@ #ifndef __MESON_SM_H__ #define __MESON_SM_H__ +/** + * meson_sm_read_efuse - read efuse memory into buffer + * + * @offset: offset from the start efuse memory + * @buffer: pointer to buffer + * @size: number of bytes to read + * @return: number of bytes read + */ ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size); +/** + * meson_sm_write_efuse - write into efuse memory from buffer + * + * @offset: offset from the start efuse memory + * @buffer: pointer to buffer + * @size: number of bytes to write + * @return: number of bytes written + */ +ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size); + #define SM_SERIAL_SIZE 12 +/** + * meson_sm_get_serial - read chip unique id into buffer + * + * @buffer: pointer to buffer + * @size: buffer size. + * @return: zero on success or -errno on failure + */ int meson_sm_get_serial(void *buffer, size_t size); enum { @@ -28,6 +53,9 @@ enum { REBOOT_REASON_WATCHDOG_REBOOT = 13, }; +/** + * meson_sm_get_reboot_reason - get reboot reason + */ int meson_sm_get_reboot_reason(void); #endif /* __MESON_SM_H__ */ -- 2.25.1
[PATCH v3 2/5] arm/mach-meson: move smc commands in cmd/meson
It is incorrect to keep commands in the arch/ folder. Signed-off-by: Alexey Romanov Reviewed-by: Mattijs Korpershoek --- MAINTAINERS | 1 + arch/arm/mach-meson/sm.c | 144 cmd/Kconfig | 7 ++ cmd/Makefile | 3 + cmd/meson/Makefile | 5 ++ cmd/meson/sm.c | 156 +++ 6 files changed, 172 insertions(+), 144 deletions(-) create mode 100644 cmd/meson/Makefile create mode 100644 cmd/meson/sm.c diff --git a/MAINTAINERS b/MAINTAINERS index 7f27ff4c20f..7a5460d4922 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -149,6 +149,7 @@ L: u-boot-amlo...@groups.io T: git https://source.denx.de/u-boot/custodians/u-boot-amlogic.git F: arch/arm/mach-meson/ F: arch/arm/include/asm/arch-meson/ +F: cmd/meson/ F: drivers/clk/meson/ F: drivers/serial/serial_meson.c F: drivers/reset/reset-meson.c diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index d6eb910689f..f2ca7e76932 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -139,145 +137,3 @@ int meson_sm_get_reboot_reason(void) /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */ return FIELD_GET(REBOOT_REASON_MASK, reason); } - -static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address; - int ret; - - if (argc < 2) - return CMD_RET_USAGE; - - address = simple_strtoul(argv[1], NULL, 0); - - ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE); - if (ret) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -#define MAX_REBOOT_REASONS 14 - -static const char *reboot_reasons[MAX_REBOOT_REASONS] = { - [REBOOT_REASON_COLD] = "cold_boot", - [REBOOT_REASON_NORMAL] = "normal", - [REBOOT_REASON_RECOVERY] = "recovery", - [REBOOT_REASON_UPDATE] = "update", - [REBOOT_REASON_FASTBOOT] = "fastboot", - [REBOOT_REASON_SUSPEND_OFF] = "suspend_off", - [REBOOT_REASON_HIBERNATE] = "hibernate", - [REBOOT_REASON_BOOTLOADER] = "bootloader", - [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot", - [REBOOT_REASON_RPMBP] = "rpmbp", - [REBOOT_REASON_CRASH_DUMP] = "crash_dump", - [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic", - [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot", -}; - -static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - const char *reason_str; - char *destarg = NULL; - int reason; - - if (argc > 1) - destarg = argv[1]; - - reason = meson_sm_get_reboot_reason(); - if (reason < 0) - return CMD_RET_FAILURE; - - if (reason >= MAX_REBOOT_REASONS || - !reboot_reasons[reason]) - reason_str = "unknown"; - else - reason_str = reboot_reasons[reason]; - - if (destarg) - env_set(destarg, reason_str); - else - printf("reboot reason: %s (%x)\n", reason_str, reason); - - return CMD_RET_SUCCESS; -} - -static int do_efuse_read(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address, offset, size; - int ret; - - if (argc < 4) - return CMD_RET_USAGE; - -offset = simple_strtoul(argv[1], NULL, 0); -size = simple_strtoul(argv[2], NULL, 0); - -address = simple_strtoul(argv[3], NULL, 0); - - ret = meson_sm_read_efuse(offset, (void *)address, size); - if (ret != size) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address, offset, size; - int ret; - - if (argc < 4) - return CMD_RET_USAGE; - -offset = simple_strtoul(argv[1], NULL, 0); -size = simple_strtoul(argv[2], NULL, 0); - -address = simple_strtoul(argv[3], NULL, 0); - - ret = meson_sm_write_efuse(offset, (void *)address, size); - if (ret != size) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -static struct cmd_tbl cmd_sm_sub[] = { - U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), - U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), - U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""), - U_BOOT_CMD_MKENT(efusewrit
[PATCH v3 3/5] doc/usage: cmd: documentation for meson/sm command
Signed-off-by: Alexey Romanov --- doc/usage/cmd/sm.rst | 44 1 file changed, 44 insertions(+) create mode 100644 doc/usage/cmd/sm.rst diff --git a/doc/usage/cmd/sm.rst b/doc/usage/cmd/sm.rst new file mode 100644 index 000..3a70c137ec9 --- /dev/null +++ b/doc/usage/cmd/sm.rst @@ -0,0 +1,44 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +Meson Security Monitor command +== + +Synopis +--- + +:: + +sm serial +sm reboot_reason [name] +sm efuseread +sm efusewrite +sm efusedump + +Description +--- + +The sm command is used to request services from the secure monitor. User +can call secure monitor to request special TEE function, for example chip +serial number info, reboot reason, etc. + +sm serial + Retrieve chip unique serial number from sm and write it to memory on + appropriate address. + +sm reboot_reason + Print reboot reason to the console, if parameter [name] isn't specified. + If parameter specified, set reboot reason string to environment variable + with this name. + +sm efuseread + Read bytes starting from from efuse memory bank and write + result to the address . + +sm efusewrite + Write into efuse memory bank, starting from , the bytes + of data, located at address . + +Configuration +- + +To use the sm command you must specify CONFIG_CMD_MESON=y -- 2.25.1
[PATCH v3 4/5] cmd/arm: meson: sm: introduce efusedump command
Using this command user can print efuse memory: $ sm efusedump 0 10 : ff 00 31 00 00 ff 66 00 00 00 ..1...f... Signed-off-by: Alexey Romanov Reviewed-by: Mattijs Korpershoek --- cmd/meson/sm.c | 36 +++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/cmd/meson/sm.c b/cmd/meson/sm.c index c2b57707258..d5eb1d6c084 100644 --- a/cmd/meson/sm.c +++ b/cmd/meson/sm.c @@ -5,6 +5,7 @@ * Author: Beniamino Galvani * Author: Vyacheslav Bocharov * Author: Neil Armstrong + * Author: Alexey Romanov */ #include @@ -119,11 +120,43 @@ static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_SUCCESS; } +static int do_efuse_dump(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong offset, size; + u8 *buffer; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + offset = simple_strtoul(argv[1], NULL, 0); + size = simple_strtoul(argv[2], NULL, 0); + buffer = malloc(size); + if (!buffer) { + pr_err("Failed to allocate %lu bytes\n", size); + return CMD_RET_FAILURE; + } + + ret = meson_sm_read_efuse(offset, (void *)buffer, size); + if (ret != size) { + ret = CMD_RET_FAILURE; + goto free_buffer; + } + + print_buffer(0, buffer, 1, size, 0); + +free_buffer: + free(buffer); + return ret; +} + static struct cmd_tbl cmd_sm_sub[] = { U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""), U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", ""), + U_BOOT_CMD_MKENT(efusedump, 3, 1, do_efuse_dump, "", ""), }; static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc, @@ -152,5 +185,6 @@ U_BOOT_CMD( "serial - read chip unique id to memory address\n" "sm reboot_reason [name] - get reboot reason and store to environment\n" "sm efuseread- read efuse to memory address\n" - "sm efusewrite- write into efuse from memory address" + "sm efusewrite- write into efuse from memory address\n" + "sm efusedump - dump efuse data range to console" ); -- 2.25.1
[PATCH v3 5/5] doc/usage: cmd: sm: documentation efusedump cmd
Signed-off-by: Alexey Romanov --- doc/usage/cmd/sm.rst | 4 1 file changed, 4 insertions(+) diff --git a/doc/usage/cmd/sm.rst b/doc/usage/cmd/sm.rst index 3a70c137ec9..beb53b3f46d 100644 --- a/doc/usage/cmd/sm.rst +++ b/doc/usage/cmd/sm.rst @@ -38,6 +38,10 @@ sm efusewrite Write into efuse memory bank, starting from , the bytes of data, located at address . +sm efusedump + Read bytes starting from from efuse memory bank and print + them to the console. + Configuration - -- 2.25.1
[PATCH v4 0/5] arch-meson: introduce efusedump command
Keeping the commands code in an arch/ is not correct. This patchset moves the meson smc commands from arch/arm/mach-meson to cmd/meson folder and also adds a new 'efusedump' command with which user can print efuse memory. Alexey Romanov (5): asm/arch-meson: add missing meson_sm_write_efuse signature arm/mach-meson: move smc commands in cmd/meson doc/usage: cmd: documentation for meson/sm command cmd/arm: meson: sm: introduce efusedump command doc/usage: cmd: sm: documentation efusedump cmd MAINTAINERS | 1 + arch/arm/include/asm/arch-meson/sm.h | 28 arch/arm/mach-meson/sm.c | 144 cmd/Kconfig | 7 + cmd/Makefile | 3 + cmd/meson/Makefile | 5 + cmd/meson/sm.c | 190 +++ doc/usage/cmd/sm.rst | 48 +++ doc/usage/index.rst | 1 + 9 files changed, 283 insertions(+), 144 deletions(-) create mode 100644 cmd/meson/Makefile create mode 100644 cmd/meson/sm.c create mode 100644 doc/usage/cmd/sm.rst -- 2.25.1
[PATCH v4 1/5] asm/arch-meson: add missing meson_sm_write_efuse signature
This function can be used by other modules. Also add comments. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- arch/arm/include/asm/arch-meson/sm.h | 28 1 file changed, 28 insertions(+) diff --git a/arch/arm/include/asm/arch-meson/sm.h b/arch/arm/include/asm/arch-meson/sm.h index f3ae46a6d6b..53b75176493 100644 --- a/arch/arm/include/asm/arch-meson/sm.h +++ b/arch/arm/include/asm/arch-meson/sm.h @@ -6,10 +6,35 @@ #ifndef __MESON_SM_H__ #define __MESON_SM_H__ +/** + * meson_sm_read_efuse - read efuse memory into buffer + * + * @offset: offset from the start efuse memory + * @buffer: pointer to buffer + * @size: number of bytes to read + * @return: number of bytes read + */ ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size); +/** + * meson_sm_write_efuse - write into efuse memory from buffer + * + * @offset: offset from the start efuse memory + * @buffer: pointer to buffer + * @size: number of bytes to write + * @return: number of bytes written + */ +ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size); + #define SM_SERIAL_SIZE 12 +/** + * meson_sm_get_serial - read chip unique id into buffer + * + * @buffer: pointer to buffer + * @size: buffer size. + * @return: zero on success or -errno on failure + */ int meson_sm_get_serial(void *buffer, size_t size); enum { @@ -28,6 +53,9 @@ enum { REBOOT_REASON_WATCHDOG_REBOOT = 13, }; +/** + * meson_sm_get_reboot_reason - get reboot reason + */ int meson_sm_get_reboot_reason(void); #endif /* __MESON_SM_H__ */ -- 2.25.1
[PATCH v4 2/5] arm/mach-meson: move smc commands in cmd/meson
It is incorrect to keep commands in the arch/ folder. Signed-off-by: Alexey Romanov Reviewed-by: Mattijs Korpershoek Reviewed-by: Neil Armstrong --- MAINTAINERS | 1 + arch/arm/mach-meson/sm.c | 144 cmd/Kconfig | 7 ++ cmd/Makefile | 3 + cmd/meson/Makefile | 5 ++ cmd/meson/sm.c | 156 +++ 6 files changed, 172 insertions(+), 144 deletions(-) create mode 100644 cmd/meson/Makefile create mode 100644 cmd/meson/sm.c diff --git a/MAINTAINERS b/MAINTAINERS index 7f27ff4c20f..7a5460d4922 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -149,6 +149,7 @@ L: u-boot-amlo...@groups.io T: git https://source.denx.de/u-boot/custodians/u-boot-amlogic.git F: arch/arm/mach-meson/ F: arch/arm/include/asm/arch-meson/ +F: cmd/meson/ F: drivers/clk/meson/ F: drivers/serial/serial_meson.c F: drivers/reset/reset-meson.c diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index d6eb910689f..f2ca7e76932 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -139,145 +137,3 @@ int meson_sm_get_reboot_reason(void) /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */ return FIELD_GET(REBOOT_REASON_MASK, reason); } - -static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address; - int ret; - - if (argc < 2) - return CMD_RET_USAGE; - - address = simple_strtoul(argv[1], NULL, 0); - - ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE); - if (ret) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -#define MAX_REBOOT_REASONS 14 - -static const char *reboot_reasons[MAX_REBOOT_REASONS] = { - [REBOOT_REASON_COLD] = "cold_boot", - [REBOOT_REASON_NORMAL] = "normal", - [REBOOT_REASON_RECOVERY] = "recovery", - [REBOOT_REASON_UPDATE] = "update", - [REBOOT_REASON_FASTBOOT] = "fastboot", - [REBOOT_REASON_SUSPEND_OFF] = "suspend_off", - [REBOOT_REASON_HIBERNATE] = "hibernate", - [REBOOT_REASON_BOOTLOADER] = "bootloader", - [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot", - [REBOOT_REASON_RPMBP] = "rpmbp", - [REBOOT_REASON_CRASH_DUMP] = "crash_dump", - [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic", - [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot", -}; - -static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - const char *reason_str; - char *destarg = NULL; - int reason; - - if (argc > 1) - destarg = argv[1]; - - reason = meson_sm_get_reboot_reason(); - if (reason < 0) - return CMD_RET_FAILURE; - - if (reason >= MAX_REBOOT_REASONS || - !reboot_reasons[reason]) - reason_str = "unknown"; - else - reason_str = reboot_reasons[reason]; - - if (destarg) - env_set(destarg, reason_str); - else - printf("reboot reason: %s (%x)\n", reason_str, reason); - - return CMD_RET_SUCCESS; -} - -static int do_efuse_read(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address, offset, size; - int ret; - - if (argc < 4) - return CMD_RET_USAGE; - -offset = simple_strtoul(argv[1], NULL, 0); -size = simple_strtoul(argv[2], NULL, 0); - -address = simple_strtoul(argv[3], NULL, 0); - - ret = meson_sm_read_efuse(offset, (void *)address, size); - if (ret != size) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong address, offset, size; - int ret; - - if (argc < 4) - return CMD_RET_USAGE; - -offset = simple_strtoul(argv[1], NULL, 0); -size = simple_strtoul(argv[2], NULL, 0); - -address = simple_strtoul(argv[3], NULL, 0); - - ret = meson_sm_write_efuse(offset, (void *)address, size); - if (ret != size) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - -static struct cmd_tbl cmd_sm_sub[] = { - U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), - U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), - U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""), - U_BOOT_CMD_M
[PATCH v4 3/5] doc/usage: cmd: documentation for meson/sm command
Added docs for Meson Security Monitor command. Signed-off-by: Alexey Romanov --- doc/usage/cmd/sm.rst | 44 doc/usage/index.rst | 1 + 2 files changed, 45 insertions(+) create mode 100644 doc/usage/cmd/sm.rst diff --git a/doc/usage/cmd/sm.rst b/doc/usage/cmd/sm.rst new file mode 100644 index 000..c41227f4b3b --- /dev/null +++ b/doc/usage/cmd/sm.rst @@ -0,0 +1,44 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +sm command +== + +Synopis +--- + +:: + +sm serial +sm reboot_reason [name] +sm efuseread +sm efusewrite +sm efusedump + +Description +--- + +The sm command is used to request services from the secure monitor. User +can call secure monitor to request special TEE function, for example chip +serial number info, reboot reason, etc. + +sm serial + Retrieve chip unique serial number from sm and write it to memory on + appropriate address. + +sm reboot_reason + Print reboot reason to the console, if parameter [name] isn't specified. + If parameter specified, set reboot reason string to environment variable + with this name. + +sm efuseread + Read bytes starting from from efuse memory bank and write + result to the address . + +sm efusewrite + Write into efuse memory bank, starting from , the bytes + of data, located at address . + +Configuration +- + +To use the sm command you must specify CONFIG_CMD_MESON=y diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 770418434ad..e34b98dae24 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -61,6 +61,7 @@ Shell commands cmd/true cmd/ums cmd/wdt + cmd/sm Booting OS -- -- 2.25.1
[PATCH v4 5/5] doc/usage: cmd: sm: documentation efusedump cmd
Added docs about sm efusedump command, that reads bytes from efuse memory bank and print them to the console. Signed-off-by: Alexey Romanov Reviewed-by: Neil Armstrong --- doc/usage/cmd/sm.rst | 4 1 file changed, 4 insertions(+) diff --git a/doc/usage/cmd/sm.rst b/doc/usage/cmd/sm.rst index c41227f4b3b..f6524a1c2e3 100644 --- a/doc/usage/cmd/sm.rst +++ b/doc/usage/cmd/sm.rst @@ -38,6 +38,10 @@ sm efusewrite Write into efuse memory bank, starting from , the bytes of data, located at address . +sm efusedump + Read bytes starting from from efuse memory bank and print + them to the console. + Configuration - -- 2.25.1
[PATCH v4 4/5] cmd/arm: meson: sm: introduce efusedump command
Using this command user can print efuse memory: $ sm efusedump 0 10 : ff 00 31 00 00 ff 66 00 00 00 ..1...f... Signed-off-by: Alexey Romanov Reviewed-by: Mattijs Korpershoek Reviewed-by: Neil Armstrong --- cmd/meson/sm.c | 36 +++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/cmd/meson/sm.c b/cmd/meson/sm.c index c2b57707258..d5eb1d6c084 100644 --- a/cmd/meson/sm.c +++ b/cmd/meson/sm.c @@ -5,6 +5,7 @@ * Author: Beniamino Galvani * Author: Vyacheslav Bocharov * Author: Neil Armstrong + * Author: Alexey Romanov */ #include @@ -119,11 +120,43 @@ static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_SUCCESS; } +static int do_efuse_dump(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong offset, size; + u8 *buffer; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + offset = simple_strtoul(argv[1], NULL, 0); + size = simple_strtoul(argv[2], NULL, 0); + buffer = malloc(size); + if (!buffer) { + pr_err("Failed to allocate %lu bytes\n", size); + return CMD_RET_FAILURE; + } + + ret = meson_sm_read_efuse(offset, (void *)buffer, size); + if (ret != size) { + ret = CMD_RET_FAILURE; + goto free_buffer; + } + + print_buffer(0, buffer, 1, size, 0); + +free_buffer: + free(buffer); + return ret; +} + static struct cmd_tbl cmd_sm_sub[] = { U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""), U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", ""), + U_BOOT_CMD_MKENT(efusedump, 3, 1, do_efuse_dump, "", ""), }; static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc, @@ -152,5 +185,6 @@ U_BOOT_CMD( "serial - read chip unique id to memory address\n" "sm reboot_reason [name] - get reboot reason and store to environment\n" "sm efuseread- read efuse to memory address\n" - "sm efusewrite- write into efuse from memory address" + "sm efusewrite- write into efuse from memory address\n" + "sm efusedump - dump efuse data range to console" ); -- 2.25.1
Re: [PATCH v1] android_ab: don't ignore ab_control_store return code
Hello! Really sorry for the noise, but please, take a look at my patch :) On Tue, Nov 28, 2023 at 02:26:34PM +0300, Alexey Romanov wrote: > ab_control_store() can return an error if writing to disk fails. > In this case, we have to pass the error code to the caller. > > Signed-off-by: Alexey Romanov > --- > boot/android_ab.c | 18 -- > 1 file changed, 16 insertions(+), 2 deletions(-) > > diff --git a/boot/android_ab.c b/boot/android_ab.c > index 73b55c196c..5a3152dd53 100644 > --- a/boot/android_ab.c > +++ b/boot/android_ab.c > @@ -337,7 +337,15 @@ int ab_select_slot(struct blk_desc *dev_desc, struct > disk_partition *part_info, > > if (store_needed) { > abc->crc32_le = ab_control_compute_crc(abc); > - ab_control_store(dev_desc, part_info, abc, 0); > + ret = ab_control_store(dev_desc, part_info, abc, 0); > + if (ret < 0) { > +#if ANDROID_AB_BACKUP_OFFSET > + free(backup_abc); > +#endif > + free(abc); > + log_err("ANDROID: failed to store boot control block: > %d\n", ret); > + return ret; > + } > } > > #if ANDROID_AB_BACKUP_OFFSET > @@ -346,8 +354,14 @@ int ab_select_slot(struct blk_desc *dev_desc, struct > disk_partition *part_info, >* to the backup offset >*/ > if (memcmp(backup_abc, abc, sizeof(*abc)) != 0) { > - ab_control_store(dev_desc, part_info, abc, > + ret = ab_control_store(dev_desc, part_info, abc, >ANDROID_AB_BACKUP_OFFSET); > + if (ret < 0) { > + free(backup_abc); > + free(abc); > + log_err("ANDROID: failed to store boot control block: > %d\n", ret); > + return ret; > + } > } > free(backup_abc); > #endif > -- > 2.39.2 > -- Thank you, Alexey
[PATCH v2] android_ab: don't ignore ab_control_store return code
ab_control_store() can return an error if writing to disk fails. In this case, we have to pass the error code to the caller. Signed-off-by: Alexey Romanov Reviewed-by: Mattijs Korpershoek --- boot/android_ab.c | 16 ++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/boot/android_ab.c b/boot/android_ab.c index 73b55c196c..af3c375e07 100644 --- a/boot/android_ab.c +++ b/boot/android_ab.c @@ -337,7 +337,14 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, if (store_needed) { abc->crc32_le = ab_control_compute_crc(abc); - ab_control_store(dev_desc, part_info, abc, 0); + ret = ab_control_store(dev_desc, part_info, abc, 0); + if (ret < 0) { +#if ANDROID_AB_BACKUP_OFFSET + free(backup_abc); +#endif + free(abc); + return ret; + } } #if ANDROID_AB_BACKUP_OFFSET @@ -346,8 +353,13 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, * to the backup offset */ if (memcmp(backup_abc, abc, sizeof(*abc)) != 0) { - ab_control_store(dev_desc, part_info, abc, + ret = ab_control_store(dev_desc, part_info, abc, ANDROID_AB_BACKUP_OFFSET); + if (ret < 0) { + free(backup_abc); + free(abc); + return ret; + } } free(backup_abc); #endif -- 2.39.2
[PATCH v1] arch: meson: add helper for boot partitition flashing
Amlogic uses its own scheme for flashing bootloader partition. This patch adds helper function that can be used by Amlogic BootROM and custom protocols. Signed-off-by: Alexey Romanov --- arch/arm/include/asm/arch-meson/nand.h | 88 arch/arm/mach-meson/Kconfig| 16 +++ arch/arm/mach-meson/Makefile | 2 +- arch/arm/mach-meson/nand.c | 133 + 4 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-meson/nand.h create mode 100644 arch/arm/mach-meson/nand.c diff --git a/arch/arm/include/asm/arch-meson/nand.h b/arch/arm/include/asm/arch-meson/nand.h new file mode 100644 index 00..5297d79dd6 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/nand.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2023 SaluteDevices, Inc. + */ + +#ifndef __MESON_NAND_H__ +#define __MESON_NAND_H__ + +#include + +#define BOOT_LOADER "bootloader" +#define BOOT_BL2"bl2" +#define BOOT_SPL"spl" +#define BOOT_TPL"tpl" +#define BOOT_FIP"fip" + +#define BL2_COPY_NUM(CONFIG_MESON_BL2_COPY_NUM) +#define TPL_COPY_NUM(CONFIG_MESON_TPL_COPY_NUM) +#define BOOT_TOTAL_PAGES1024 +#define TPL_SIZE_PER_COPY 0x20 +#define BL2_SIZE(64 * 1024) + +struct meson_spi_nand_info_page { + char magic[8]; /* Magic header of info page. */ + /* Info page version, +1 when you update this struct. */ + u8 version; /* 1 for now. */ + u8 mode;/* 1 discrete, 0 compact. */ + u8 bl2_num; /* bl2 copy number. */ + u8 fip_num; /* fip copy number. */ + union { + struct { + u8 rd_max; /* spi nand max read io. */ + u8 oob_offset; /* User bytes offset. */ + u8 planes_per_lun; + u8 rsv; + u32 fip_start; /* Start pages. */ + u32 fip_pages; /* Pages per fip. */ + u32 page_size; /* spi nand page size (bytes). */ + u32 page_per_blk; /* Page number per block. */ + u32 oob_size; /* Valid oob size (bytes). */ + u32 bbt_start; /* BBT start pages. */ + u32 bbt_valid; /* BBT valid offset pages. */ + u32 bbt_size; /* BBT occupied bytes. */ + } __packed spinand; /* spi nand. */ + struct { + u32 reserved; + } emmc; + } dev; +} __packed; + +/** + * meson_bootloader_copy_num - get bootloader numbers of copies + * + * @part_name: partition name + * @return: number of copies of the specified bootloader partition + */ +int meson_bootloader_copy_num(const char *part_name); + +/** + * meson_bootloader_copy_size - get bootloader copy size in bytes + * + * @mtd: nand mtd instance + * @part_name: partition name + * @return: bootloader partition (fox example, BL2) copy size in bytes + */ +int meson_bootloader_copy_size(struct mtd_info *mtd, const char *part_name); + +/** + * meson_bootloader_write_info_pages - write bootloader metadata to nand + * + * @return: zero on success or error code on failure. + */ +int meson_bootloader_write_info_pages(void); + +/** + * meson_bootloader_write_bl2 - write bl2 to nand + * + * @mtd: nand mtd instance + * @buff: buffer to read from + * @offset: offset in flash + * @size: buffer length + * @flags: flags modifying the behaviour of the write to NAND + * @return: zero on success or error code on failure + */ +int meson_bootloader_write_bl2(struct mtd_info *mtd, void *buff, u32 offset, + size_t size, int flags); + +#endif diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index d6c8905806..7b75ed9a2b 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -96,4 +96,20 @@ config SYS_CONFIG_NAME Based on this option include/configs/.h header will be used for board configuration. +config MESON_BL2_COPY_NUM + depends on ADNL || FASTBOOT_FLASH + int "Number of BL2 copies written to storage" + default 0 + help + The ADNL / fastboot protocol writes several copies of BL2 bootloader + during firmware update process. + +config MESON_TPL_COPY_NUM + depends on ADNL || FASTBOOT_FLASH + int "Number of TPL copies written to storage" + default 0 + help + The ADNL / fastboot protocol writes several copies of TPL bootloader + during firmware update process. + endif diff --git a/arch/arm/mach-meson/Makefile b/arch/arm/mach-meson/Makefile index 535b0878b9..460626bca9 100644 --- a/arch/arm/mach-meson/Makefile
[PATCH v1] fastboot: introduce 'oem board' subcommand
Currently, fastboot protocol in U-Boot has no opportunity to execute vendor custom code with verifed boot. This patch introduce new fastboot subcommand fastboot oem board:, which allow to run custom oem_board function. Default implementation is __weak. Vendor must redefine it in board/ folder with his own logic. For example, some vendors have their custom nand/emmc partition flashing or erasing. Here some typical command for such use cases: - flashing: $ fastboot stage bootloader.img $ fastboot oem board:write_bootloader - erasing: $ fastboot oem board:erase_env Signed-off-by: Alexey Romanov --- drivers/fastboot/Kconfig | 7 +++ drivers/fastboot/fb_command.c | 15 +++ include/fastboot.h| 1 + 3 files changed, 23 insertions(+) diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 3cfeea4837..4c955cabab 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -241,6 +241,13 @@ config FASTBOOT_OEM_RUN this feature if you are using verified boot, as it will allow an attacker to bypass any restrictions you have in place. +config FASTBOOT_OEM_BOARD + bool "Enable the 'oem board' command" + help + This extends the fastboot protocol with an "oem board" command. This + command allows running vendor custom code defined in board/ files. + Otherwise, it will do nothing and send fastboot fail. + endif # FASTBOOT endmenu diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 71cfaec6e9..4d2b451f46 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -39,6 +39,7 @@ static void reboot_recovery(char *, char *); static void oem_format(char *, char *); static void oem_partconf(char *, char *); static void oem_bootbus(char *, char *); +static void oem_board(char *, char *); static void run_ucmd(char *, char *); static void run_acmd(char *, char *); @@ -106,6 +107,10 @@ static const struct { .command = "oem run", .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_RUN, (run_ucmd), (NULL)) }, + [FASTBOOT_COMMAND_OEM_BOARD] = { + .command = "oem board", + .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_BOARD, (oem_board), (NULL)) + }, [FASTBOOT_COMMAND_UCMD] = { .command = "UCmd", .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), (NULL)) @@ -489,3 +494,13 @@ static void __maybe_unused oem_bootbus(char *cmd_parameter, char *response) else fastboot_okay(NULL, response); } + +void __weak fastboot_oem_board(char *cmd_parameter, void *data, u32 size, char *response) +{ + fastboot_fail("oem board function not defined", response); +} + +static void __maybe_unused oem_board(char *cmd_parameter, char *response) +{ + fastboot_oem_board(cmd_parameter, fastboot_buf_addr, image_size, response); +} diff --git a/include/fastboot.h b/include/fastboot.h index 296451f89d..06c1f26b6c 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -37,6 +37,7 @@ enum { FASTBOOT_COMMAND_OEM_PARTCONF, FASTBOOT_COMMAND_OEM_BOOTBUS, FASTBOOT_COMMAND_OEM_RUN, + FASTBOOT_COMMAND_OEM_BOARD, FASTBOOT_COMMAND_ACMD, FASTBOOT_COMMAND_UCMD, FASTBOOT_COMMAND_COUNT -- 2.30.1