[PATCH v2 01/14] cmd: cpu: migrate cpu command to U_BOOT_CMD_WITH_SUBCMDS()

Migrate cpu command to use U_BOOT_CMD_WITH_SUBCMDS() helper macro, to reduce duplicated code. This also fixes the cpu command on boards that enable CONFIG_NEEDS_MANUAL_RELOC.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com --- NOTE: this series depends on the following "events" patch: https://lore.kernel.org/u-boot/20220515184029.2169025-2-ovpanait@gmail.com/
Changes in v2: - New patch.
cmd/cpu.c | 39 ++++++++------------------------------- 1 file changed, 8 insertions(+), 31 deletions(-)
diff --git a/cmd/cpu.c b/cmd/cpu.c index 67dbb044b5..2ca4d05ae8 100644 --- a/cmd/cpu.c +++ b/cmd/cpu.c @@ -82,36 +82,13 @@ static int do_cpu_detail(struct cmd_tbl *cmdtp, int flag, int argc, return 0; }
-static struct cmd_tbl cmd_cpu_sub[] = { - U_BOOT_CMD_MKENT(list, 2, 1, do_cpu_list, "", ""), - U_BOOT_CMD_MKENT(detail, 4, 0, do_cpu_detail, "", ""), -}; - -/* - * Process a cpu sub-command - */ -static int do_cpu(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - struct cmd_tbl *c = NULL; - - /* Strip off leading 'cpu' command argument */ - argc--; - argv++; - - if (argc) - c = find_cmd_tbl(argv[0], cmd_cpu_sub, - ARRAY_SIZE(cmd_cpu_sub)); - - if (c) - return c->cmd(cmdtp, flag, argc, argv); - else - return CMD_RET_USAGE; -} - -U_BOOT_CMD( - cpu, 2, 1, do_cpu, - "display information about CPUs", +#if CONFIG_IS_ENABLED(SYS_LONGHELP) +static char cpu_help_text[] = "list - list available CPUs\n" "cpu detail - show CPU detail" -); + ; +#endif + +U_BOOT_CMD_WITH_SUBCMDS(cpu, "display information about CPUs", cpu_help_text, + U_BOOT_SUBCMD_MKENT(list, 1, 1, do_cpu_list), + U_BOOT_SUBCMD_MKENT(detail, 1, 0, do_cpu_detail));

Relocate cpu_ops pointers when CONFIG_NEEDS_MANUAL_RELOC is enabled.
The (gd->flags & GD_FLG_RELOC) check was added to make sure the reloc_done logic works for drivers that use DM_FLAG_PRE_RELOC.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - New patch.
drivers/cpu/cpu-uclass.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c index a5cda6a62c..71e5900d70 100644 --- a/drivers/cpu/cpu-uclass.c +++ b/drivers/cpu/cpu-uclass.c @@ -14,6 +14,9 @@ #include <dm/lists.h> #include <dm/root.h> #include <linux/err.h> +#include <relocate.h> + +DECLARE_GLOBAL_DATA_PTR;
int cpu_probe_all(void) { @@ -136,9 +139,36 @@ static int uclass_cpu_init(struct uclass *uc) return ret; }
+static int uclass_cpu_post_bind(struct udevice *dev) +{ + if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC) && + (gd->flags & GD_FLG_RELOC)) { + struct cpu_ops *ops = cpu_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->get_desc) + MANUAL_RELOC(ops->get_desc); + if (ops->get_info) + MANUAL_RELOC(ops->get_info); + if (ops->get_count) + MANUAL_RELOC(ops->get_count); + if (ops->get_vendor) + MANUAL_RELOC(ops->get_vendor); + if (ops->is_current) + MANUAL_RELOC(ops->is_current); + + reloc_done++; + } + } + + return 0; +} + UCLASS_DRIVER(cpu) = { .id = UCLASS_CPU, .name = "cpu", .flags = DM_UC_FLAG_SEQ_ALIAS, .init = uclass_cpu_init, + .post_bind = uclass_cpu_post_bind, };

in16/out16 routines seem to not be used anywhere in microblaze code, so remove them.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 33 --------------------------------- 1 file changed, 33 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 645f7cb038..d1b0453caf 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -220,39 +220,6 @@ __setup_exceptions: or r0, r0, r0 .end __setup_exceptions
-/* - * Read 16bit little endian - */ - .text - .global in16 - .ent in16 - .align 2 -in16: lhu r3, r0, r5 - bslli r4, r3, 8 - bsrli r3, r3, 8 - andi r4, r4, 0xffff - or r3, r3, r4 - rtsd r15, 8 - sext16 r3, r3 - .end in16 - -/* - * Write 16bit little endian - * first parameter(r5) - address, second(r6) - short value - */ - .text - .global out16 - .ent out16 - .align 2 -out16: bslli r3, r6, 8 - bsrli r6, r6, 8 - andi r3, r3, 0xffff - or r3, r3, r6 - sh r3, r0, r5 - rtsd r15, 8 - or r0, r0, r0 - .end out16 - /* * Relocate u-boot */

XILINX_USE_DCACHE macro was removed in 7556fa09e0e ("microblaze: Simplify cache handling"), but it was still used in a couple of places.
Replace those occurences with CONFIG_DCACHE.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
(no changes since v1)
arch/microblaze/cpu/cache.c | 2 +- arch/microblaze/lib/bootm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index aa832d6be6..b6126de194 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -49,7 +49,7 @@ void dcache_enable(void)
void dcache_disable(void) { -#ifdef XILINX_USE_DCACHE +#ifdef CONFIG_DCACHE flush_cache(0, XILINX_DCACHE_BYTE_SIZE); #endif MSRCLR(0x80); diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c index 12ea32488e..b652d2767a 100644 --- a/arch/microblaze/lib/bootm.c +++ b/arch/microblaze/lib/bootm.c @@ -57,7 +57,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) "(fake run for tracing)" : ""); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
-#ifdef XILINX_USE_DCACHE +#ifdef CONFIG_DCACHE flush_cache(0, XILINX_DCACHE_BYTE_SIZE); #endif

Replace CONFIG_DCACHE with a Kconfig option more limited in scope - XILINX_MICROBLAZE0_USE_WDC. It should be enabled if the processor supports the "wdc" (Write to Data Cache) instruction. It will be used to guard "wdc" invocations in microblaze cache code.
Also, drop all ifdefs around flush_cache() calls and only keep one CONFIG_IS_ENABLED() guard within flush_cache() itself.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - added CONFIG_SPL_XILINX_MICROBLAZE0_USE_WDC symbol
arch/microblaze/Kconfig | 4 ---- arch/microblaze/cpu/cache.c | 15 ++++++++++----- arch/microblaze/lib/bootm.c | 2 -- board/xilinx/microblaze-generic/Kconfig | 11 +++++++++++ 4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index d7d1b21970..5a2e91104f 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -25,10 +25,6 @@ config TARGET_MICROBLAZE_GENERIC
endchoice
-config DCACHE - bool "Enable dcache support" - default y - config ICACHE bool "Enable icache support" default y diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index b6126de194..4e8e228a22 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -49,26 +49,31 @@ void dcache_enable(void)
void dcache_disable(void) { -#ifdef CONFIG_DCACHE flush_cache(0, XILINX_DCACHE_BYTE_SIZE); -#endif + MSRCLR(0x80); }
void flush_cache(ulong addr, ulong size) { int i; - for (i = 0; i < size; i += 4) + for (i = 0; i < size; i += 4) { asm volatile ( #ifdef CONFIG_ICACHE "wic %0, r0;" #endif "nop;" -#ifdef CONFIG_DCACHE + : + : "r" (addr + i) + : "memory"); + + if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) { + asm volatile ( "wdc.flush %0, r0;" -#endif "nop;" : : "r" (addr + i) : "memory"); + } + } } diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c index b652d2767a..dba6226ce5 100644 --- a/arch/microblaze/lib/bootm.c +++ b/arch/microblaze/lib/bootm.c @@ -57,9 +57,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) "(fake run for tracing)" : ""); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
-#ifdef CONFIG_DCACHE flush_cache(0, XILINX_DCACHE_BYTE_SIZE); -#endif
if (!fake) { /* diff --git a/board/xilinx/microblaze-generic/Kconfig b/board/xilinx/microblaze-generic/Kconfig index 117b476f3f..b00ce6f59a 100644 --- a/board/xilinx/microblaze-generic/Kconfig +++ b/board/xilinx/microblaze-generic/Kconfig @@ -63,4 +63,15 @@ config XILINX_MICROBLAZE0_VECTOR_BASE_ADDR Memory address location of the exception vector table. It is configurable via the C_BASE_VECTORS hdl parameter.
+config XILINX_MICROBLAZE0_USE_WDC + bool "MicroBlaze wdc instruction support" + default y + help + Enable this option if the MicroBlaze processor is configured with + support for the "wdc" (Write to Data Cache) instruction. + +config SPL_XILINX_MICROBLAZE0_USE_WDC + bool + default XILINX_MICROBLAZE0_USE_WDC + endif

Replace CONFIG_ICACHE with a Kconfig option more limited in scope - XILINX_MICROBLAZE0_USE_WIC. It should be enabled if the processor supports the "wic" (Write to Instruction Cache) instruction. It will be used to guard "wic" invocations in microblaze cache code.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - added CONFIG_SPL_XILINX_MICROBLAZE0_USE_WIC symbol
arch/microblaze/Kconfig | 4 ---- arch/microblaze/cpu/cache.c | 6 +++--- board/xilinx/microblaze-generic/Kconfig | 11 +++++++++++ 3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 5a2e91104f..a25a95a013 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -25,10 +25,6 @@ config TARGET_MICROBLAZE_GENERIC
endchoice
-config ICACHE - bool "Enable icache support" - default y - source "board/xilinx/Kconfig" source "board/xilinx/microblaze-generic/Kconfig"
diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index 4e8e228a22..b6bbc215b3 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -58,14 +58,14 @@ void flush_cache(ulong addr, ulong size) { int i; for (i = 0; i < size; i += 4) { - asm volatile ( -#ifdef CONFIG_ICACHE + if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WIC)) { + asm volatile ( "wic %0, r0;" -#endif "nop;" : : "r" (addr + i) : "memory"); + }
if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) { asm volatile ( diff --git a/board/xilinx/microblaze-generic/Kconfig b/board/xilinx/microblaze-generic/Kconfig index b00ce6f59a..98b4814b95 100644 --- a/board/xilinx/microblaze-generic/Kconfig +++ b/board/xilinx/microblaze-generic/Kconfig @@ -74,4 +74,15 @@ config SPL_XILINX_MICROBLAZE0_USE_WDC bool default XILINX_MICROBLAZE0_USE_WDC
+config XILINX_MICROBLAZE0_USE_WIC + bool "MicroBlaze wic instruction support" + default y + help + Enable this option if the MicroBlaze processor is configured with + support for the "wic" (Write to Instruction Cache) instruction. + +config SPL_XILINX_MICROBLAZE0_USE_WIC + bool + default XILINX_MICROBLAZE0_USE_WIC + endif

Factor out icache/dcache components from flush_cache() function. Call the newly added __flush_icache()/__flush_dcache() functions inside icache_disable() and dcache_disable(), respectively. There is no need to flush both caches when disabling a particular cache type.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
(no changes since v1)
arch/microblaze/cpu/cache.c | 55 ++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index b6bbc215b3..e362a34a79 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -10,6 +10,34 @@ #include <asm/asm.h> #include <asm/cache.h>
+static void __invalidate_icache(ulong addr, ulong size) +{ + if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WIC)) { + for (int i = 0; i < size; i += 4) { + asm volatile ( + "wic %0, r0;" + "nop;" + : + : "r" (addr + i) + : "memory"); + } + } +} + +static void __flush_dcache(ulong addr, ulong size) +{ + if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) { + for (int i = 0; i < size; i += 4) { + asm volatile ( + "wdc.flush %0, r0;" + "nop;" + : + : "r" (addr + i) + : "memory"); + } + } +} + int dcache_status(void) { int i = 0; @@ -38,7 +66,8 @@ void icache_enable(void) void icache_disable(void) { /* we are not generate ICACHE size -> flush whole cache */ - flush_cache(0, 32768); + __invalidate_icache(0, 32768); + MSRCLR(0x20); }
@@ -49,31 +78,13 @@ void dcache_enable(void)
void dcache_disable(void) { - flush_cache(0, XILINX_DCACHE_BYTE_SIZE); + __flush_dcache(0, XILINX_DCACHE_BYTE_SIZE);
MSRCLR(0x80); }
void flush_cache(ulong addr, ulong size) { - int i; - for (i = 0; i < size; i += 4) { - if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WIC)) { - asm volatile ( - "wic %0, r0;" - "nop;" - : - : "r" (addr + i) - : "memory"); - } - - if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) { - asm volatile ( - "wdc.flush %0, r0;" - "nop;" - : - : "r" (addr + i) - : "memory"); - } - } + __invalidate_icache(addr, size); + __flush_dcache(addr, size); }

Replace XILINX_DCACHE_BYTE_SIZE macro with two Kconfig symbols for instruction and data caches sizes, respectively: CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE
Also, get rid of the hardcoded value in icache_disable().
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - added separate Kconfig symbols for icache/dcache
arch/microblaze/cpu/cache.c | 5 ++--- arch/microblaze/cpu/start.S | 4 ++-- arch/microblaze/lib/bootm.c | 2 +- board/xilinx/microblaze-generic/Kconfig | 16 ++++++++++++++++ include/configs/microblaze-generic.h | 4 ---- 5 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index e362a34a79..d5c0afd935 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -65,8 +65,7 @@ void icache_enable(void)
void icache_disable(void) { - /* we are not generate ICACHE size -> flush whole cache */ - __invalidate_icache(0, 32768); + __invalidate_icache(0, CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE);
MSRCLR(0x20); } @@ -78,7 +77,7 @@ void dcache_enable(void)
void dcache_disable(void) { - __flush_dcache(0, XILINX_DCACHE_BYTE_SIZE); + __flush_dcache(0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE);
MSRCLR(0x80); } diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index d1b0453caf..356ca05392 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -53,7 +53,7 @@ _start:
/* Flush cache before enable cache */ addik r5, r0, 0 - addik r6, r0, XILINX_DCACHE_BYTE_SIZE + addik r6, r0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE bralid r15, flush_cache nop
@@ -284,7 +284,7 @@ relocate_code:
/* Flush caches to ensure consistency */ addik r5, r0, 0 - addik r6, r0, XILINX_DCACHE_BYTE_SIZE + addik r6, r0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE bralid r15, flush_cache nop
diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c index dba6226ce5..48e05333a6 100644 --- a/arch/microblaze/lib/bootm.c +++ b/arch/microblaze/lib/bootm.c @@ -57,7 +57,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) "(fake run for tracing)" : ""); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
- flush_cache(0, XILINX_DCACHE_BYTE_SIZE); + flush_cache(0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE);
if (!fake) { /* diff --git a/board/xilinx/microblaze-generic/Kconfig b/board/xilinx/microblaze-generic/Kconfig index 98b4814b95..a6743cadf4 100644 --- a/board/xilinx/microblaze-generic/Kconfig +++ b/board/xilinx/microblaze-generic/Kconfig @@ -85,4 +85,20 @@ config SPL_XILINX_MICROBLAZE0_USE_WIC bool default XILINX_MICROBLAZE0_USE_WIC
+config XILINX_MICROBLAZE0_DCACHE_SIZE + int "Default data cache size" + default 32768 + help + This fallback size will be used when no dcache info can be found in + the device tree, or when the data cache is flushed very early in the + boot process, before device tree is available. + +config XILINX_MICROBLAZE0_ICACHE_SIZE + int "Default instruction cache size" + default 32768 + help + This fallback size will be used when no icache info can be found in + the device tree, or when the instruction cache is flushed very early + in the boot process, before device tree is available. + endif diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h index 663837f33d..7b064eacb2 100644 --- a/include/configs/microblaze-generic.h +++ b/include/configs/microblaze-generic.h @@ -30,10 +30,6 @@ # define CONFIG_SYS_MAX_FLASH_SECT 2048 #endif
-#ifndef XILINX_DCACHE_BYTE_SIZE -#define XILINX_DCACHE_BYTE_SIZE 32768 -#endif - /* size of console buffer */ #define CONFIG_SYS_CBSIZE 512 /* max number of command args */

All flush_cache() calls in microblaze code are supposed to flush the entire instruction and data caches, so introduce flush_cache_all() helper to handle this.
Also, provide implementations for flush_dcache_all() and invalidate_icache_all() so that icache and dcache u-boot commands can work.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - adjusted for newly added CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE and CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE Kconfig symbols
arch/microblaze/cpu/cache.c | 20 ++++++++++++++++++-- arch/microblaze/cpu/start.S | 8 ++------ arch/microblaze/include/asm/cache.h | 5 +++++ arch/microblaze/lib/bootm.c | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index d5c0afd935..b99b8c1706 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -24,6 +24,11 @@ static void __invalidate_icache(ulong addr, ulong size) } }
+void invalidate_icache_all(void) +{ + __invalidate_icache(0, CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE); +} + static void __flush_dcache(ulong addr, ulong size) { if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) { @@ -38,6 +43,11 @@ static void __flush_dcache(ulong addr, ulong size) } }
+void flush_dcache_all(void) +{ + __flush_dcache(0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE); +} + int dcache_status(void) { int i = 0; @@ -65,7 +75,7 @@ void icache_enable(void)
void icache_disable(void) { - __invalidate_icache(0, CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE); + invalidate_icache_all();
MSRCLR(0x20); } @@ -77,7 +87,7 @@ void dcache_enable(void)
void dcache_disable(void) { - __flush_dcache(0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE); + flush_dcache_all();
MSRCLR(0x80); } @@ -87,3 +97,9 @@ void flush_cache(ulong addr, ulong size) __invalidate_icache(addr, size); __flush_dcache(addr, size); } + +void flush_cache_all(void) +{ + invalidate_icache_all(); + flush_dcache_all(); +} diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 356ca05392..7f7b5f5cb5 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -52,9 +52,7 @@ _start: #endif
/* Flush cache before enable cache */ - addik r5, r0, 0 - addik r6, r0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE - bralid r15, flush_cache + bralid r15, flush_cache_all nop
/* enable instruction and data cache */ @@ -283,9 +281,7 @@ relocate_code: addk r20, r20, r23
/* Flush caches to ensure consistency */ - addik r5, r0, 0 - addik r6, r0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE - bralid r15, flush_cache + bralid r15, flush_cache_all nop
2: addi r5, r31, 0 /* gd is initialized in board_r.c */ diff --git a/arch/microblaze/include/asm/cache.h b/arch/microblaze/include/asm/cache.h index baee01a0e2..c39b66dd7d 100644 --- a/arch/microblaze/include/asm/cache.h +++ b/arch/microblaze/include/asm/cache.h @@ -18,4 +18,9 @@ #define ARCH_DMA_MINALIGN 16 #endif
+/** + * flush_cache_all - flush the entire instruction/data caches + */ +void flush_cache_all(void); + #endif /* __MICROBLAZE_CACHE_H__ */ diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c index 48e05333a6..af946b8642 100644 --- a/arch/microblaze/lib/bootm.c +++ b/arch/microblaze/lib/bootm.c @@ -57,7 +57,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) "(fake run for tracing)" : ""); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
- flush_cache(0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE); + flush_cache_all();
if (!fake) { /*

Introduce a minimal cpuinfo structure to hold cache related info. The instruction/data cache size and cache line size are initialized early in the boot to default Kconfig values. They will be overwritten with data from PVR/dtb if the microblaze UCLASS_CPU driver is enabled.
The cpuinfo struct was placed in global_data to allow the microblaze UCLASS_CPU driver to also run before relocation (initialized global data should be read-only before relocation).
gd_cpuinfo() helper macro was added to avoid volatile "-Wdiscarded-qualifiers" warnings when using the pointer directly.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - New patch.
arch/microblaze/cpu/Makefile | 2 +- arch/microblaze/cpu/cache.c | 14 ++++++--- arch/microblaze/cpu/cpuinfo.c | 20 +++++++++++++ arch/microblaze/cpu/start.S | 7 +++++ arch/microblaze/include/asm/cpuinfo.h | 35 +++++++++++++++++++++++ arch/microblaze/include/asm/global_data.h | 5 ++++ 6 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 arch/microblaze/cpu/cpuinfo.c create mode 100644 arch/microblaze/include/asm/cpuinfo.h
diff --git a/arch/microblaze/cpu/Makefile b/arch/microblaze/cpu/Makefile index f7a83d07b6..5388a21550 100644 --- a/arch/microblaze/cpu/Makefile +++ b/arch/microblaze/cpu/Makefile @@ -5,5 +5,5 @@
extra-y = start.o obj-y = irq.o -obj-y += interrupts.o cache.o exception.o timer.o +obj-y += interrupts.o cache.o exception.o timer.o cpuinfo.o obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index b99b8c1706..cd8507901d 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -9,11 +9,16 @@ #include <cpu_func.h> #include <asm/asm.h> #include <asm/cache.h> +#include <asm/cpuinfo.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR;
static void __invalidate_icache(ulong addr, ulong size) { if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WIC)) { - for (int i = 0; i < size; i += 4) { + for (int i = 0; i < size; + i += gd_cpuinfo()->icache_line_length) { asm volatile ( "wic %0, r0;" "nop;" @@ -26,13 +31,14 @@ static void __invalidate_icache(ulong addr, ulong size)
void invalidate_icache_all(void) { - __invalidate_icache(0, CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE); + __invalidate_icache(0, gd_cpuinfo()->icache_size); }
static void __flush_dcache(ulong addr, ulong size) { if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) { - for (int i = 0; i < size; i += 4) { + for (int i = 0; i < size; + i += gd_cpuinfo()->dcache_line_length) { asm volatile ( "wdc.flush %0, r0;" "nop;" @@ -45,7 +51,7 @@ static void __flush_dcache(ulong addr, ulong size)
void flush_dcache_all(void) { - __flush_dcache(0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE); + __flush_dcache(0, gd_cpuinfo()->dcache_size); }
int dcache_status(void) diff --git a/arch/microblaze/cpu/cpuinfo.c b/arch/microblaze/cpu/cpuinfo.c new file mode 100644 index 0000000000..3f0b1d2c04 --- /dev/null +++ b/arch/microblaze/cpu/cpuinfo.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022, Ovidiu Panait ovpanait@gmail.com + */ +#include <common.h> +#include <asm/cpuinfo.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +void microblaze_early_cpuinfo_init(void) +{ + struct microblaze_cpuinfo *ci = gd_cpuinfo(); + + ci->icache_size = CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE; + ci->icache_line_length = 4; + + ci->dcache_size = CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE; + ci->dcache_line_length = 4; +} diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 7f7b5f5cb5..ad400a4be5 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -51,6 +51,13 @@ _start: nop #endif
+ /* + * Initialize global data cpuinfo with default values (cache + * size, cache line size, etc). + */ + bralid r15, microblaze_early_cpuinfo_init + nop + /* Flush cache before enable cache */ bralid r15, flush_cache_all nop diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h new file mode 100644 index 0000000000..c27dd40af7 --- /dev/null +++ b/arch/microblaze/include/asm/cpuinfo.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2022, Ovidiu Panait ovpanait@gmail.com + */ + +#ifndef __ASM_MICROBLAZE_CPUINFO_H +#define __ASM_MICROBLAZE_CPUINFO_H + +/** + * struct microblaze_cpuinfo - CPU info for microblaze processor core. + * + * @icache_size: Size of instruction cache memory in bytes. + * @icache_line_length: Instruction cache line length in bytes. + * @dcache_size: Size of data cache memory in bytes. + * @dcache_line_length: Data cache line length in bytes. + */ +struct microblaze_cpuinfo { + u32 icache_size; + u32 icache_line_length; + + u32 dcache_size; + u32 dcache_line_length; +}; + +/** + * microblaze_early_cpuinfo_init() - Initialize cpuinfo with default values. + * + * Initializes the global data cpuinfo structure with default values (cache + * size, cache line size, etc.). It is called very early in the boot process + * (start.S codepath right before the first cache flush call) to ensure that + * cache related operations are properly handled. + */ +void microblaze_early_cpuinfo_init(void); + +#endif /* __ASM_MICROBLAZE_CPUINFO_H */ diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index 05868ac4f5..93506dec89 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -8,12 +8,17 @@ #ifndef __ASM_GBL_DATA_H #define __ASM_GBL_DATA_H
+#include <asm/cpuinfo.h> + /* Architecture-specific global data */ struct arch_global_data { + struct microblaze_cpuinfo cpuinfo; };
#include <asm-generic/global_data.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r31")
+#define gd_cpuinfo() ((struct microblaze_cpuinfo *)&gd->arch.cpuinfo) + #endif /* __ASM_GBL_DATA_H */

út 31. 5. 2022 v 20:15 odesílatel Ovidiu Panait ovpanait@gmail.com napsal:
Introduce a minimal cpuinfo structure to hold cache related info. The instruction/data cache size and cache line size are initialized early in the boot to default Kconfig values. They will be overwritten with data from PVR/dtb if the microblaze UCLASS_CPU driver is enabled.
The cpuinfo struct was placed in global_data to allow the microblaze UCLASS_CPU driver to also run before relocation (initialized global data should be read-only before relocation).
gd_cpuinfo() helper macro was added to avoid volatile "-Wdiscarded-qualifiers" warnings when using the pointer directly.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com
Changes in v2:
- New patch.
arch/microblaze/cpu/Makefile | 2 +- arch/microblaze/cpu/cache.c | 14 ++++++--- arch/microblaze/cpu/cpuinfo.c | 20 +++++++++++++ arch/microblaze/cpu/start.S | 7 +++++ arch/microblaze/include/asm/cpuinfo.h | 35 +++++++++++++++++++++++ arch/microblaze/include/asm/global_data.h | 5 ++++ 6 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 arch/microblaze/cpu/cpuinfo.c create mode 100644 arch/microblaze/include/asm/cpuinfo.h
diff --git a/arch/microblaze/cpu/Makefile b/arch/microblaze/cpu/Makefile index f7a83d07b6..5388a21550 100644 --- a/arch/microblaze/cpu/Makefile +++ b/arch/microblaze/cpu/Makefile @@ -5,5 +5,5 @@
extra-y = start.o obj-y = irq.o -obj-y += interrupts.o cache.o exception.o timer.o +obj-y += interrupts.o cache.o exception.o timer.o cpuinfo.o obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index b99b8c1706..cd8507901d 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -9,11 +9,16 @@ #include <cpu_func.h> #include <asm/asm.h> #include <asm/cache.h> +#include <asm/cpuinfo.h> +#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
static void __invalidate_icache(ulong addr, ulong size) { if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WIC)) {
for (int i = 0; i < size; i += 4) {
for (int i = 0; i < size;
i += gd_cpuinfo()->icache_line_length) { asm volatile ( "wic %0, r0;" "nop;"
@@ -26,13 +31,14 @@ static void __invalidate_icache(ulong addr, ulong size)
void invalidate_icache_all(void) {
__invalidate_icache(0, CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE);
__invalidate_icache(0, gd_cpuinfo()->icache_size);
}
static void __flush_dcache(ulong addr, ulong size) { if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) {
for (int i = 0; i < size; i += 4) {
for (int i = 0; i < size;
i += gd_cpuinfo()->dcache_line_length) { asm volatile ( "wdc.flush %0, r0;" "nop;"
@@ -45,7 +51,7 @@ static void __flush_dcache(ulong addr, ulong size)
void flush_dcache_all(void) {
__flush_dcache(0, CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE);
__flush_dcache(0, gd_cpuinfo()->dcache_size);
}
int dcache_status(void) diff --git a/arch/microblaze/cpu/cpuinfo.c b/arch/microblaze/cpu/cpuinfo.c new file mode 100644 index 0000000000..3f0b1d2c04 --- /dev/null +++ b/arch/microblaze/cpu/cpuinfo.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2022, Ovidiu Panait ovpanait@gmail.com
- */
+#include <common.h> +#include <asm/cpuinfo.h> +#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+void microblaze_early_cpuinfo_init(void) +{
struct microblaze_cpuinfo *ci = gd_cpuinfo();
ci->icache_size = CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE;
ci->icache_line_length = 4;
ci->dcache_size = CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE;
ci->dcache_line_length = 4;
+} diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 7f7b5f5cb5..ad400a4be5 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -51,6 +51,13 @@ _start: nop #endif
/*
* Initialize global data cpuinfo with default values (cache
* size, cache line size, etc).
*/
bralid r15, microblaze_early_cpuinfo_init
nop
/* Flush cache before enable cache */ bralid r15, flush_cache_all nop
diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h new file mode 100644 index 0000000000..c27dd40af7 --- /dev/null +++ b/arch/microblaze/include/asm/cpuinfo.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (C) 2022, Ovidiu Panait ovpanait@gmail.com
- */
+#ifndef __ASM_MICROBLAZE_CPUINFO_H +#define __ASM_MICROBLAZE_CPUINFO_H
+/**
- struct microblaze_cpuinfo - CPU info for microblaze processor core.
- @icache_size: Size of instruction cache memory in bytes.
- @icache_line_length: Instruction cache line length in bytes.
- @dcache_size: Size of data cache memory in bytes.
- @dcache_line_length: Data cache line length in bytes.
- */
+struct microblaze_cpuinfo {
u32 icache_size;
u32 icache_line_length;
u32 dcache_size;
u32 dcache_line_length;
Feel free to create a separate patch on the top of this series which introduces arch_print_bdinfo() to also print it out or use your cpu driver to have a way to get information about caches.
Thanks, Michal

Align microblaze with the other architectures and provide an implementation for flush_dcache_range(). Also, remove the microblaze exception in drivers/core/device.c.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - Added debug message for invalid range.
arch/microblaze/cpu/cache.c | 11 +++++++++++ drivers/core/device.c | 5 ----- 2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/arch/microblaze/cpu/cache.c b/arch/microblaze/cpu/cache.c index cd8507901d..829e6c7ae6 100644 --- a/arch/microblaze/cpu/cache.c +++ b/arch/microblaze/cpu/cache.c @@ -49,6 +49,17 @@ static void __flush_dcache(ulong addr, ulong size) } }
+void flush_dcache_range(unsigned long start, unsigned long end) +{ + if (start >= end) { + debug("Invalid dcache range - start: 0x%08lx end: 0x%08lx\n", + start, end); + return; + } + + __flush_dcache(start, end - start); +} + void flush_dcache_all(void) { __flush_dcache(0, gd_cpuinfo()->dcache_size); diff --git a/drivers/core/device.c b/drivers/core/device.c index 3ab2583df3..03155e9867 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -328,13 +328,8 @@ static void *alloc_priv(int size, uint flags) * within this range at the start. The driver can then * use normal flush-after-write, invalidate-before-read * procedures. - * - * TODO(sjg@chromium.org): Drop this microblaze - * exception. */ -#ifndef CONFIG_MICROBLAZE flush_dcache_range((ulong)priv, (ulong)priv + size); -#endif } } else { priv = calloc(1, size);

Provide a static Kconfig value for the target FPGA archtitecture, as it is done in Linux. The cpu-uclass driver will cross-check it with the value read from PVR10 register.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - New patch.
board/xilinx/microblaze-generic/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/board/xilinx/microblaze-generic/Kconfig b/board/xilinx/microblaze-generic/Kconfig index a6743cadf4..90f79cfb94 100644 --- a/board/xilinx/microblaze-generic/Kconfig +++ b/board/xilinx/microblaze-generic/Kconfig @@ -38,6 +38,14 @@ config XILINX_MICROBLAZE0_HW_VER string "Core version number" default "7.10.d"
+config XILINX_MICROBLAZE0_FPGA_FAMILY + string "Targeted FPGA family" + default "virtex5" + help + This option contains info about the target FPGA architecture + (Zynq-7000, UltraScale+ Kintex, etc) that the MicroBlaze soft core is + implemented on. It corresponds to the C_FAMILY hdl parameter. + config XILINX_MICROBLAZE0_USR_EXCEP bool "MicroBlaze user exception support" default y

Add helper code for PVR (Processor Version Register) data handling. It will be used by the UCLASS_CPU driver to populate cpuinfo fields at runtime.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - New patch.
arch/microblaze/cpu/Makefile | 1 + arch/microblaze/cpu/pvr.c | 41 ++++++++++++++ arch/microblaze/include/asm/pvr.h | 75 +++++++++++++++++++++++++ board/xilinx/microblaze-generic/Kconfig | 8 +++ 4 files changed, 125 insertions(+) create mode 100644 arch/microblaze/cpu/pvr.c create mode 100644 arch/microblaze/include/asm/pvr.h
diff --git a/arch/microblaze/cpu/Makefile b/arch/microblaze/cpu/Makefile index 5388a21550..96eb40f6f2 100644 --- a/arch/microblaze/cpu/Makefile +++ b/arch/microblaze/cpu/Makefile @@ -6,4 +6,5 @@ extra-y = start.o obj-y = irq.o obj-y += interrupts.o cache.o exception.o timer.o cpuinfo.o +obj-$(CONFIG_XILINX_MICROBLAZE0_PVR) += pvr.o obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/microblaze/cpu/pvr.c b/arch/microblaze/cpu/pvr.c new file mode 100644 index 0000000000..23c0f912d4 --- /dev/null +++ b/arch/microblaze/cpu/pvr.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022, Ovidiu Panait ovpanait@gmail.com + */ +#include <common.h> +#include <asm/asm.h> +#include <asm/pvr.h> + +int microblaze_cpu_has_pvr_full(void) +{ + u32 msr, pvr0; + + MFS(msr, rmsr); + if (!(msr & PVR_MSR_BIT)) + return 0; + + get_pvr(0, pvr0); + debug("%s: pvr0 is 0x%08x\n", __func__, pvr0); + + if (!(pvr0 & PVR0_PVR_FULL_MASK)) + return 0; + + return 1; +} + +void microblaze_get_all_pvrs(u32 pvr[PVR_FULL_COUNT]) +{ + get_pvr(0, pvr[0]); + get_pvr(1, pvr[1]); + get_pvr(2, pvr[2]); + get_pvr(3, pvr[3]); + get_pvr(4, pvr[4]); + get_pvr(5, pvr[5]); + get_pvr(6, pvr[6]); + get_pvr(7, pvr[7]); + get_pvr(8, pvr[8]); + get_pvr(9, pvr[9]); + get_pvr(10, pvr[10]); + get_pvr(11, pvr[11]); + get_pvr(12, pvr[12]); +} diff --git a/arch/microblaze/include/asm/pvr.h b/arch/microblaze/include/asm/pvr.h new file mode 100644 index 0000000000..bfe159af79 --- /dev/null +++ b/arch/microblaze/include/asm/pvr.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2022, Ovidiu Panait ovpanait@gmail.com + */ + +#ifndef __ASM_MICROBLAZE_PVR_H +#define __ASM_MICROBLAZE_PVR_H + +#include <asm/asm.h> + +#define PVR_FULL_COUNT 13 /* PVR0 - PVR12 */ + +#define __get_pvr(val, reg) \ + __asm__ __volatile__ ("mfs %0," #reg : "=r" (val) :: "memory") +#define get_pvr(pvrid, val) \ + __get_pvr(val, rpvr ## pvrid) + +#define PVR_MSR_BIT 0x00000400 + +/* PVR0 masks */ +#define PVR0_PVR_FULL_MASK 0x80000000 +#define PVR0_VERSION_MASK 0x0000FF00 + +/* PVR4 masks - ICache configs */ +#define PVR4_ICACHE_LINE_LEN_MASK 0x00E00000 /* ICLL */ +#define PVR4_ICACHE_BYTE_SIZE_MASK 0x001F0000 /* ICBS */ + +/* PVR5 masks - DCache configs */ +#define PVR5_DCACHE_LINE_LEN_MASK 0x00E00000 /* DCLL */ +#define PVR5_DCACHE_BYTE_SIZE_MASK 0x001F0000 /* DCBS */ + +/* PVR10 masks - FPGA family */ +#define PVR10_TARGET_FAMILY_MASK 0xFF000000 + +/* PVR11 masks - MMU */ +#define PVR11_USE_MMU 0xC0000000 + +/* PVR access macros */ +#define PVR_VERSION(pvr) \ + ((pvr[0] & PVR0_VERSION_MASK) >> 8) + +#define PVR_ICACHE_LINE_LEN(pvr) \ + ((1 << ((pvr[4] & PVR4_ICACHE_LINE_LEN_MASK) >> 21)) << 2) +#define PVR_ICACHE_BYTE_SIZE(pvr) \ + (1 << ((pvr[4] & PVR4_ICACHE_BYTE_SIZE_MASK) >> 16)) + +#define PVR_DCACHE_LINE_LEN(pvr) \ + ((1 << ((pvr[5] & PVR5_DCACHE_LINE_LEN_MASK) >> 21)) << 2) +#define PVR_DCACHE_BYTE_SIZE(pvr) \ + (1 << ((pvr[5] & PVR5_DCACHE_BYTE_SIZE_MASK) >> 16)) + +#define PVR_USE_MMU(pvr) \ + ((pvr[11] & PVR11_USE_MMU) >> 30) + +#define PVR_TARGET_FAMILY(pvr) \ + ((pvr[10] & PVR10_TARGET_FAMILY_MASK) >> 24) + +/** + * microblaze_cpu_has_pvr_full() - Check for full PVR support + * + * Check MSR register for PVR support and, if applicable, check the PVR0 + * register for full PVR support. + * + * Return: 1 if there is full PVR support, 0 otherwise. + */ +int microblaze_cpu_has_pvr_full(void); + +/** + * microblaze_get_all_pvrs() - Copy PVR0-PVR12 to destination array + * + * @pvr: destination array of size PVR_FULL_COUNT + */ +void microblaze_get_all_pvrs(u32 pvr[PVR_FULL_COUNT]); + +#endif /* __ASM_MICROBLAZE_PVR_H */ diff --git a/board/xilinx/microblaze-generic/Kconfig b/board/xilinx/microblaze-generic/Kconfig index 90f79cfb94..dd5eacef52 100644 --- a/board/xilinx/microblaze-generic/Kconfig +++ b/board/xilinx/microblaze-generic/Kconfig @@ -109,4 +109,12 @@ config XILINX_MICROBLAZE0_ICACHE_SIZE the device tree, or when the instruction cache is flushed very early in the boot process, before device tree is available.
+config XILINX_MICROBLAZE0_PVR + bool "MicroBlaze PVR support" + help + Enables helper functions and macros needed to manipulate PVR + (Processor Version Register) data. Currently, only the microblaze + UCLASS_CPU driver makes use of this feature to retrieve CPU info at + runtime. + endif

Add a basic CPU driver that retrieves information about the microblaze CPU core. cpu_ops handlers are implemented so that the "cpu" command can work properly:
U-Boot-mONStR> cpu list 0: cpu@0 MicroBlaze @ 50MHz, Rev: 11.0, FPGA family: zynq7000 U-Boot-mONStR> cpu detail 0: cpu@0 MicroBlaze @ 50MHz, Rev: 11.0, FPGA family: zynq7000 ID = 0, freq = 50 MHz: L1 cache, MMU
Note: cpu_ver_lookup[] and family_string_lookup[] arrays were imported from linux.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com ---
Changes in v2: - Refactored completely. - Fixed v9.X version codes. - Added support for cross-checking PVR and static data. - Added support for "cpu" command.
arch/microblaze/cpu/cpuinfo.c | 111 ++++++++++++++++ arch/microblaze/include/asm/cpuinfo.h | 79 +++++++++++ drivers/cpu/Kconfig | 9 ++ drivers/cpu/Makefile | 1 + drivers/cpu/microblaze_cpu.c | 180 ++++++++++++++++++++++++++ 5 files changed, 380 insertions(+) create mode 100644 drivers/cpu/microblaze_cpu.c
diff --git a/arch/microblaze/cpu/cpuinfo.c b/arch/microblaze/cpu/cpuinfo.c index 3f0b1d2c04..f021f4e5e2 100644 --- a/arch/microblaze/cpu/cpuinfo.c +++ b/arch/microblaze/cpu/cpuinfo.c @@ -8,6 +8,117 @@
DECLARE_GLOBAL_DATA_PTR;
+#if CONFIG_IS_ENABLED(CPU_MICROBLAZE) +/* These key value are as per MBV field in PVR0 */ +static const struct microblaze_version_map cpu_ver_lookup[] = { + {"5.00.a", 0x01}, + {"5.00.b", 0x02}, + {"5.00.c", 0x03}, + {"6.00.a", 0x04}, + {"6.00.b", 0x06}, + {"7.00.a", 0x05}, + {"7.00.b", 0x07}, + {"7.10.a", 0x08}, + {"7.10.b", 0x09}, + {"7.10.c", 0x0a}, + {"7.10.d", 0x0b}, + {"7.20.a", 0x0c}, + {"7.20.b", 0x0d}, + {"7.20.c", 0x0e}, + {"7.20.d", 0x0f}, + {"7.30.a", 0x10}, + {"7.30.b", 0x11}, + {"8.00.a", 0x12}, + {"8.00.b", 0x13}, + {"8.10.a", 0x14}, + {"8.20.a", 0x15}, + {"8.20.b", 0x16}, + {"8.30.a", 0x17}, + {"8.40.a", 0x18}, + {"8.40.b", 0x19}, + {"8.50.a", 0x1a}, + {"8.50.b", 0x1c}, + {"8.50.c", 0x1e}, + {"9.0", 0x1b}, + {"9.1", 0x1d}, + {"9.2", 0x1f}, + {"9.3", 0x20}, + {"9.4", 0x21}, + {"9.5", 0x22}, + {"9.6", 0x23}, + {"10.0", 0x24}, + {"11.0", 0x25}, + {NULL, 0}, +}; + +static const struct microblaze_version_map family_string_lookup[] = { + {"virtex2", 0x4}, + {"virtex2pro", 0x5}, + {"spartan3", 0x6}, + {"virtex4", 0x7}, + {"virtex5", 0x8}, + {"spartan3e", 0x9}, + {"spartan3a", 0xa}, + {"spartan3an", 0xb}, + {"spartan3adsp", 0xc}, + {"spartan6", 0xd}, + {"virtex6", 0xe}, + {"virtex7", 0xf}, + /* FIXME There is no key code defined for spartan2 */ + {"spartan2", 0xf0}, + {"kintex7", 0x10}, + {"artix7", 0x11}, + {"zynq7000", 0x12}, + {"UltraScale Virtex", 0x13}, + {"UltraScale Kintex", 0x14}, + {"UltraScale+ Zynq", 0x15}, + {"UltraScale+ Virtex", 0x16}, + {"UltraScale+ Kintex", 0x17}, + {"Spartan7", 0x18}, + {NULL, 0}, +}; + +static const char *lookup_string(u32 code, + const struct microblaze_version_map *entry) +{ + for (; entry->string; ++entry) + if (entry->code == code) + return entry->string; + + return "(unknown)"; +} + +static const u32 lookup_code(const char *string, + const struct microblaze_version_map *entry) +{ + for (; entry->string; ++entry) + if (!strcmp(entry->string, string)) + return entry->code; + + return 0; +} + +const char *microblaze_lookup_fpga_family_string(const u32 code) +{ + return lookup_string(code, family_string_lookup); +} + +const char *microblaze_lookup_cpu_version_string(const u32 code) +{ + return lookup_string(code, cpu_ver_lookup); +} + +const u32 microblaze_lookup_fpga_family_code(const char *string) +{ + return lookup_code(string, family_string_lookup); +} + +const u32 microblaze_lookup_cpu_version_code(const char *string) +{ + return lookup_code(string, cpu_ver_lookup); +} +#endif /* CONFIG_CPU_MICROBLAZE */ + void microblaze_early_cpuinfo_init(void) { struct microblaze_cpuinfo *ci = gd_cpuinfo(); diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h index c27dd40af7..86d2c8a034 100644 --- a/arch/microblaze/include/asm/cpuinfo.h +++ b/arch/microblaze/include/asm/cpuinfo.h @@ -13,6 +13,11 @@ * @icache_line_length: Instruction cache line length in bytes. * @dcache_size: Size of data cache memory in bytes. * @dcache_line_length: Data cache line length in bytes. + * @use_mmu: MMU support flag. + * @cpu_freq: Cpu clock frequency in Hz. + * @addr_size: Address bus width in bits. + * @ver_code: Cpu version code. + * @fpga_code: FPGA family version code. */ struct microblaze_cpuinfo { u32 icache_size; @@ -20,8 +25,82 @@ struct microblaze_cpuinfo {
u32 dcache_size; u32 dcache_line_length; + +#if CONFIG_IS_ENABLED(CPU_MICROBLAZE) + u32 use_mmu; + u32 cpu_freq; + u32 addr_size; + + u32 ver_code; + u32 fpga_code; +#endif /* CONFIG_CPU_MICROBLAZE */ +}; + +/** + * struct microblaze_version_data - Maps a hex version code to a cpu/fpga name. + */ +struct microblaze_version_map { + const char *string; + const u32 code; };
+/** + * microblaze_lookup_cpu_version_code() - Get hex version code for the + * specified cpu name string. + * + * This function searches the cpu_ver_lookup[] array for the hex version code + * associated with a specific CPU name. The version code is returned if a match + * is found, otherwise 0. + * + * @string: cpu name string + * + * Return: >0 if the entry is found, 0 otherwise. + */ +const u32 microblaze_lookup_cpu_version_code(const char *string); + +/** + * microblaze_lookup_fpga_family_code() - Get hex version code for the + * specified fpga family name. + * + * This function searches the family_string_lookup[] array for the hex version + * code associated with a specific fpga family name. The version code is + * returned if a match is found, otherwise 0. + * + * @string: fpga family name string + * + * Return: >0 if the entry is found, 0 otherwise. + */ +const u32 microblaze_lookup_fpga_family_code(const char *string); + +/** + * microblaze_lookup_cpu_version_string() - Get cpu name for the specified cpu + * version code. + * + * This function searches the cpu_ver_lookup[] array for the cpu name string + * associated with a specific version code. The cpu name is returned if a match + * is found, otherwise "(unknown)". + * + * @code: cpu version code + * + * Return: Pointer to the cpu name if the entry is found, otherwise "(unknown)". + */ +const char *microblaze_lookup_cpu_version_string(const u32 code); + +/** + * microblaze_lookup_fpga_family_string() - Get fpga family name for the + * specified version code. + * + * This function searches the family_string_lookup[] array for the fpga family + * name string associated with a specific version code. The fpga family name is + * returned if a match is found, otherwise "(unknown)". + * + * @code: fpga family version code + * + * Return: Pointer to the fpga family name if the entry is found, otherwise + * "(unknown)". + */ +const char *microblaze_lookup_fpga_family_string(const u32 code); + /** * microblaze_early_cpuinfo_init() - Initialize cpuinfo with default values. * diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig index 789728167c..21874335c8 100644 --- a/drivers/cpu/Kconfig +++ b/drivers/cpu/Kconfig @@ -19,3 +19,12 @@ config CPU_RISCV depends on CPU && RISCV help Support CPU cores for RISC-V architecture. + +config CPU_MICROBLAZE + bool "Enable Microblaze CPU driver" + depends on CPU && MICROBLAZE + select EVENT + select DM_EVENT + select XILINX_MICROBLAZE0_PVR + help + Support CPU cores for Microblaze architecture. diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile index c8532637ca..20884b1795 100644 --- a/drivers/cpu/Makefile +++ b/drivers/cpu/Makefile @@ -11,4 +11,5 @@ obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o obj-$(CONFIG_ARCH_AT91) += at91_cpu.o obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o +obj-$(CONFIG_CPU_MICROBLAZE) += microblaze_cpu.o obj-$(CONFIG_SANDBOX) += cpu_sandbox.o diff --git a/drivers/cpu/microblaze_cpu.c b/drivers/cpu/microblaze_cpu.c new file mode 100644 index 0000000000..969a1047e5 --- /dev/null +++ b/drivers/cpu/microblaze_cpu.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022, Ovidiu Panait ovpanait@gmail.com + */ +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <asm/cpuinfo.h> +#include <asm/global_data.h> +#include <asm/pvr.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define update_cpuinfo_pvr(pvr, ci, name) \ +{ \ + u32 tmp = PVR_##name(pvr); \ + if (ci != tmp) \ + printf("PVR value for " #name " does not match static data!\n");\ + ci = tmp; \ +} + +static int microblaze_cpu_probe_all(void *ctx, struct event *event) +{ + int ret; + + ret = cpu_probe_all(); + if (ret) + return log_msg_ret("Microblaze cpus probe failed\n", ret); + + return 0; +} +EVENT_SPY(EVT_DM_POST_INIT, microblaze_cpu_probe_all); + +static void microblaze_set_cpuinfo_pvr(struct microblaze_cpuinfo *ci) +{ + u32 pvr[PVR_FULL_COUNT]; + + microblaze_get_all_pvrs(pvr); + + update_cpuinfo_pvr(pvr, ci->icache_size, ICACHE_BYTE_SIZE); + update_cpuinfo_pvr(pvr, ci->icache_line_length, ICACHE_LINE_LEN); + + update_cpuinfo_pvr(pvr, ci->dcache_size, DCACHE_BYTE_SIZE); + update_cpuinfo_pvr(pvr, ci->dcache_line_length, DCACHE_LINE_LEN); + + update_cpuinfo_pvr(pvr, ci->use_mmu, USE_MMU); + update_cpuinfo_pvr(pvr, ci->ver_code, VERSION); + update_cpuinfo_pvr(pvr, ci->fpga_code, TARGET_FAMILY); +} + +static void microblaze_set_cpuinfo_static(struct udevice *dev, + struct microblaze_cpuinfo *ci) +{ + const char *hw_ver = CONFIG_XILINX_MICROBLAZE0_HW_VER; + const char *fpga_family = CONFIG_XILINX_MICROBLAZE0_FPGA_FAMILY; + + ci->icache_size = dev_read_u32_default(dev, "i-cache-size", 0); + ci->icache_line_length = dev_read_u32_default(dev, + "i-cache-line-size", 0); + + ci->dcache_size = dev_read_u32_default(dev, "d-cache-size", 0); + ci->dcache_line_length = dev_read_u32_default(dev, + "d-cache-line-size", 0); + + ci->cpu_freq = dev_read_u32_default(dev, "clock-frequency", 0); + ci->addr_size = dev_read_u32_default(dev, "xlnx,addr-size", 32); + ci->use_mmu = dev_read_u32_default(dev, "xlnx,use-mmu", 0); + + ci->ver_code = microblaze_lookup_cpu_version_code(hw_ver); + ci->fpga_code = microblaze_lookup_fpga_family_code(fpga_family); +} + +static int microblaze_cpu_probe(struct udevice *dev) +{ + microblaze_set_cpuinfo_static(dev, gd_cpuinfo()); + + if (microblaze_cpu_has_pvr_full()) + microblaze_set_cpuinfo_pvr(gd_cpuinfo()); + else + debug("No PVR support. Using only static CPU info.\n"); + + return 0; +} + +static int microblaze_cpu_get_desc(const struct udevice *dev, char *buf, + int size) +{ + struct microblaze_cpuinfo *ci = gd_cpuinfo(); + const char *cpu_ver, *fpga_family; + u32 cpu_freq_mhz; + int ret; + + cpu_freq_mhz = ci->cpu_freq / 1000000; + cpu_ver = microblaze_lookup_cpu_version_string(ci->ver_code); + fpga_family = microblaze_lookup_fpga_family_string(ci->fpga_code); + + ret = snprintf(buf, size, + "MicroBlaze @ %uMHz, Rev: %s, FPGA family: %s", + cpu_freq_mhz, cpu_ver, fpga_family); + + return 0; +} + +static int microblaze_cpu_get_info(const struct udevice *dev, + struct cpu_info *info) +{ + struct microblaze_cpuinfo *ci = gd_cpuinfo(); + + info->cpu_freq = ci->cpu_freq; + info->address_width = ci->addr_size; + + if (ci->icache_size || ci->dcache_size) + info->features |= BIT(CPU_FEAT_L1_CACHE); + + if (ci->use_mmu) + info->features |= BIT(CPU_FEAT_MMU); + + return 0; +} + +static int microblaze_cpu_get_count(const struct udevice *dev) +{ + return 1; +} + +static const struct cpu_ops microblaze_cpu_ops = { + .get_desc = microblaze_cpu_get_desc, + .get_info = microblaze_cpu_get_info, + .get_count = microblaze_cpu_get_count, +}; + +static const struct udevice_id microblaze_cpu_ids[] = { + { .compatible = "xlnx,microblaze-11.0" }, + { .compatible = "xlnx,microblaze-10.0" }, + { .compatible = "xlnx,microblaze-9.6" }, + { .compatible = "xlnx,microblaze-9.5" }, + { .compatible = "xlnx,microblaze-9.4" }, + { .compatible = "xlnx,microblaze-9.3" }, + { .compatible = "xlnx,microblaze-9.2" }, + { .compatible = "xlnx,microblaze-9.1" }, + { .compatible = "xlnx,microblaze-9.0" }, + { .compatible = "xlnx,microblaze-8.50.c" }, + { .compatible = "xlnx,microblaze-8.50.b" }, + { .compatible = "xlnx,microblaze-8.50.a" }, + { .compatible = "xlnx,microblaze-8.40.b" }, + { .compatible = "xlnx,microblaze-8.40.a" }, + { .compatible = "xlnx,microblaze-8.30.a" }, + { .compatible = "xlnx,microblaze-8.20.b" }, + { .compatible = "xlnx,microblaze-8.20.a" }, + { .compatible = "xlnx,microblaze-8.10.a" }, + { .compatible = "xlnx,microblaze-8.00.b" }, + { .compatible = "xlnx,microblaze-8.00.a" }, + { .compatible = "xlnx,microblaze-7.30.b" }, + { .compatible = "xlnx,microblaze-7.30.a" }, + { .compatible = "xlnx,microblaze-7.20.d" }, + { .compatible = "xlnx,microblaze-7.20.c" }, + { .compatible = "xlnx,microblaze-7.20.b" }, + { .compatible = "xlnx,microblaze-7.20.a" }, + { .compatible = "xlnx,microblaze-7.10.d" }, + { .compatible = "xlnx,microblaze-7.10.c" }, + { .compatible = "xlnx,microblaze-7.10.b" }, + { .compatible = "xlnx,microblaze-7.10.a" }, + { .compatible = "xlnx,microblaze-7.00.b" }, + { .compatible = "xlnx,microblaze-7.00.a" }, + { .compatible = "xlnx,microblaze-6.00.b" }, + { .compatible = "xlnx,microblaze-6.00.a" }, + { .compatible = "xlnx,microblaze-5.00.c" }, + { .compatible = "xlnx,microblaze-5.00.b" }, + { .compatible = "xlnx,microblaze-5.00.a" }, + { } +}; + +U_BOOT_DRIVER(microblaze_cpu) = { + .name = "microblaze_cpu", + .id = UCLASS_CPU, + .of_match = microblaze_cpu_ids, + .probe = microblaze_cpu_probe, + .ops = µblaze_cpu_ops, + .flags = DM_FLAG_PRE_RELOC, +};

út 31. 5. 2022 v 20:14 odesílatel Ovidiu Panait ovpanait@gmail.com napsal:
Migrate cpu command to use U_BOOT_CMD_WITH_SUBCMDS() helper macro, to reduce duplicated code. This also fixes the cpu command on boards that enable CONFIG_NEEDS_MANUAL_RELOC.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com
NOTE: this series depends on the following "events" patch: https://lore.kernel.org/u-boot/20220515184029.2169025-2-ovpanait@gmail.com/
Changes in v2:
- New patch.
cmd/cpu.c | 39 ++++++++------------------------------- 1 file changed, 8 insertions(+), 31 deletions(-)
diff --git a/cmd/cpu.c b/cmd/cpu.c index 67dbb044b5..2ca4d05ae8 100644 --- a/cmd/cpu.c +++ b/cmd/cpu.c @@ -82,36 +82,13 @@ static int do_cpu_detail(struct cmd_tbl *cmdtp, int flag, int argc, return 0; }
-static struct cmd_tbl cmd_cpu_sub[] = {
U_BOOT_CMD_MKENT(list, 2, 1, do_cpu_list, "", ""),
U_BOOT_CMD_MKENT(detail, 4, 0, do_cpu_detail, "", ""),
-};
-/*
- Process a cpu sub-command
- */
-static int do_cpu(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
-{
struct cmd_tbl *c = NULL;
/* Strip off leading 'cpu' command argument */
argc--;
argv++;
if (argc)
c = find_cmd_tbl(argv[0], cmd_cpu_sub,
ARRAY_SIZE(cmd_cpu_sub));
if (c)
return c->cmd(cmdtp, flag, argc, argv);
else
return CMD_RET_USAGE;
-}
-U_BOOT_CMD(
cpu, 2, 1, do_cpu,
"display information about CPUs",
+#if CONFIG_IS_ENABLED(SYS_LONGHELP) +static char cpu_help_text[] = "list - list available CPUs\n" "cpu detail - show CPU detail" -);
;
+#endif
+U_BOOT_CMD_WITH_SUBCMDS(cpu, "display information about CPUs", cpu_help_text,
U_BOOT_SUBCMD_MKENT(list, 1, 1, do_cpu_list),
U_BOOT_SUBCMD_MKENT(detail, 1, 0, do_cpu_detail));
-- 2.25.1
From my point of view this series looks good. I have sent v2 of mb
conversion rela and I prefer to apply this on the top. There is actually one change needed bralid/brlid in one patch but I have already did it and test it on the HW. Will queue for the next u-boot version.
Thanks, Michal

Hi Michal,
On 07.06.2022 11:33, Michal Simek wrote:
[Please note: This e-mail is from an EXTERNAL e-mail address]
út 31. 5. 2022 v 20:14 odesílatel Ovidiu Panait ovpanait@gmail.com napsal:
Migrate cpu command to use U_BOOT_CMD_WITH_SUBCMDS() helper macro, to reduce duplicated code. This also fixes the cpu command on boards that enable CONFIG_NEEDS_MANUAL_RELOC.
Signed-off-by: Ovidiu Panait ovpanait@gmail.com
NOTE: this series depends on the following "events" patch: https://lore.kernel.org/u-boot/20220515184029.2169025-2-ovpanait@gmail.com/
[...]
From my point of view this series looks good. I have sent v2 of mb conversion rela and I prefer to apply this on the top. There is actually one change needed bralid/brlid in one patch but I have already did it and test it on the HW. Will queue for the next u-boot version.
Thanks for the feedback! Could you also take in the following event patch that fixes the pointers after relocation (the cpu driver makes use of the events feature)? Without this, in my testing the event handlers are not called at all after relocation:
https://lore.kernel.org/u-boot/20220515184029.2169025-2-ovpanait@gmail.com/
It seems it is not currently applied to the 20220607-cache branch of u-boot-microblaze repo.
Thanks!
Ovidiu
Thanks, Michal
-- Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91 w: www.monstr.eu p: +42-0-721842854 Maintainer of Linux kernel - Xilinx Microblaze Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs
participants (3)
-
Michal Simek
-
Ovidiu Panait
-
Ovidiu Panait