[U-Boot] [PATCH v4 1/2] armv7m: add instruction & data cache support

Marek Vasut marex at denx.de
Mon Mar 27 20:34:32 UTC 2017


On 03/27/2017 10:02 PM, Vikas Manocha wrote:
> This patch adds armv7m instruction & data cache support.
> 
> Signed-off-by: Vikas Manocha <vikas.manocha at st.com>
> cc: Christophe KERELLO <christophe.kerello at st.com>
> ---
> 
> Changed in v4:
> - invalidate_dcache_range() & flush_dcache_range() function added.
> - blank lines added.
> - comments added for registers, functions & barriers.
> - register names changed for better clarity.
> - typecasting moved to macro definitions.
> 
> Changed in v3:
> - uint32 replcaed with u32.
> - multiple read of hardware register replaced with single.
> - pointers replaced with macros for base address.
> - register names added as comment for system control block registers.
> 
> Changed in v2:
> - changed strucures for memory mapped cache registers to macros
> - added lines better readability.
> - replaced magic numbers with macros.
> 
>  arch/arm/cpu/armv7m/Makefile  |   3 +-
>  arch/arm/cpu/armv7m/cache.c   | 336 ++++++++++++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/armv7m.h |  26 +++-
>  arch/arm/lib/Makefile         |   2 +
>  4 files changed, 363 insertions(+), 4 deletions(-)
>  create mode 100644 arch/arm/cpu/armv7m/cache.c
> 
> diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
> index e1a6c40..93c9085 100644
> --- a/arch/arm/cpu/armv7m/Makefile
> +++ b/arch/arm/cpu/armv7m/Makefile
> @@ -6,6 +6,5 @@
>  #
>  
>  extra-y := start.o
> -obj-y += cpu.o
> -
> +obj-y += cpu.o cache.o
>  obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> diff --git a/arch/arm/cpu/armv7m/cache.c b/arch/arm/cpu/armv7m/cache.c
> new file mode 100644
> index 0000000..162cfe3
> --- /dev/null
> +++ b/arch/arm/cpu/armv7m/cache.c
> @@ -0,0 +1,336 @@
> +/*
> + * (C) Copyright 2017
> + * Vikas Manocha, ST Micoelectronics, vikas.manocha at st.com.
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <asm/armv7m.h>
> +#include <asm/io.h>
> +
> +/* Cache maintenance operation registers */
> +
> +#define V7M_CACHE_REG_ICIALLU		((u32 *)(V7M_CACHE_MAINT_BASE + 0x00))
                                                 ^^^^^^^^^^^^^^^^^^^^^
                                                Drop this whole part,
it's a register offset, not address. Just calculate the address
in-place. The cast is also not needed.

> +#define INVAL_ICACHE_POU		0
> +#define V7M_CACHE_REG_ICIMVALU		((u32 *)(V7M_CACHE_MAINT_BASE + 0x08))
> +#define V7M_CACHE_REG_DCIMVAC		((u32 *)(V7M_CACHE_MAINT_BASE + 0x0C))
> +#define V7M_CACHE_REG_DCISW		((u32 *)(V7M_CACHE_MAINT_BASE + 0x10))
> +#define V7M_CACHE_REG_DCCMVAU		((u32 *)(V7M_CACHE_MAINT_BASE + 0x14))
> +#define V7M_CACHE_REG_DCCMVAC		((u32 *)(V7M_CACHE_MAINT_BASE + 0x18))
> +#define V7M_CACHE_REG_DCCSW		((u32 *)(V7M_CACHE_MAINT_BASE + 0x1C))
> +#define V7M_CACHE_REG_DCCIMVAC		((u32 *)(V7M_CACHE_MAINT_BASE + 0x20))
> +#define V7M_CACHE_REG_DCCISW		((u32 *)(V7M_CACHE_MAINT_BASE + 0x24))
> +#define WAYS_SHIFT			30
> +#define SETS_SHIFT			5
> +
> +/* armv7m processor feature registers */
> +
> +#define V7M_PROC_REG_CLIDR		((u32 *)(V7M_PROC_FTR_BASE + 0x00))
> +#define V7M_PROC_REG_CTR		((u32 *)(V7M_PROC_FTR_BASE + 0x04))
> +#define V7M_PROC_REG_CCSIDR		((u32 *)(V7M_PROC_FTR_BASE + 0x08))
> +#define MASK_NUM_WAYS			GENMASK(12, 3)
> +#define MASK_NUM_SETS			GENMASK(27, 13)
> +#define CLINE_SIZE_MASK			GENMASK(2, 0)
> +#define NUM_WAYS_SHIFT			3
> +#define NUM_SETS_SHIFT			13

Well use those macros in MASK_* above ...

> +#define V7M_PROC_REG_CSSELR		((u32 *)(V7M_PROC_FTR_BASE + 0x0C))
> +#define SEL_I_OR_D			BIT(0)
> +
> +enum cache_type {
> +	DCACHE,
> +	ICACHE,
> +};
> +
> +/* PoU : Point of Unification, Poc: Point of Coherency */
> +enum cache_action {
> +	INVALIDATE_POU,		/* i-cache invalidate by address */
> +	INVALIDATE_POC,		/* d-cache invalidate by address */
> +	INVALIDATE_SET_WAY,	/* d-cache invalidate by sets/ways */
> +	FLUSH_POU,		/* d-cache clean by address to the PoU */
> +	FLUSH_POC,		/* d-cache clean by address to the PoC */
> +	FLUSH_SET_WAY,		/* d-cache clean by sets/ways */
> +	FLUSH_INVAL_POC,	/* d-cache clean & invalidate by addr to PoC */
> +	FLUSH_INVAL_SET_WAY,	/* d-cache clean & invalidate by set/ways */
> +};
> +
> +#ifndef CONFIG_SYS_DCACHE_OFF
> +struct dcache_config {
> +	u32 ways;
> +	u32 sets;
> +};
> +
> +static void get_cache_ways_sets(struct dcache_config *cache)
> +{
> +	u32 cache_size_id = readl(V7M_PROC_REG_CCSIDR);
> +
> +	cache->ways = (cache_size_id & MASK_NUM_WAYS) >> NUM_WAYS_SHIFT;
> +	cache->sets = (cache_size_id & MASK_NUM_SETS) >> NUM_SETS_SHIFT;
> +}
> +
> +/*
> + * Return the io register to perform required cache action like clean or clean
> + * & invalidate by sets/ways.
> + */
> +static u32 *get_action_reg_set_ways(enum cache_action action)
> +{
> +	switch (action) {
> +	case INVALIDATE_SET_WAY:
> +		return V7M_CACHE_REG_DCISW;
> +	case FLUSH_SET_WAY:
> +		return V7M_CACHE_REG_DCCSW;
> +	case FLUSH_INVAL_SET_WAY:
> +		return V7M_CACHE_REG_DCCISW;
> +	default:
> +		break;
> +	};
> +
> +	return NULL;
> +}
> +
> +/*
> + * Return the io register to perform required cache action like clean or clean
> + * & invalidate by adddress or range.
> + */
> +static u32 *get_action_reg_range(enum cache_action action)
> +{
> +	switch (action) {
> +	case INVALIDATE_POU:
> +		return V7M_CACHE_REG_ICIMVALU;
> +	case INVALIDATE_POC:
> +		return V7M_CACHE_REG_DCIMVAC;
> +	case FLUSH_POU:
> +		return V7M_CACHE_REG_DCCMVAU;
> +	case FLUSH_POC:
> +		return V7M_CACHE_REG_DCCMVAC;
> +	case FLUSH_INVAL_POC:
> +		return V7M_CACHE_REG_DCCIMVAC;
> +	default:
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +static u32 get_cline_size(enum cache_type type)
> +{
> +	u32 size;
> +
> +	if (type == DCACHE)
> +		clrbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D));
> +	else if (type == ICACHE)
> +		setbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D));
> +	/* Make sure cache selection is effective for next memory access */
> +	dsb();
> +
> +	size = readl(V7M_PROC_REG_CCSIDR) & CLINE_SIZE_MASK;
> +	/* Size enocoded as 2 less than log(no_of_words_in_cache_line) base 2 */
> +	size = 1 << (size + 2);
> +	debug("cache line size is %d\n", size);
> +
> +	return size;
> +}
> +
> +/* Perform the action like invalidate/clean on a range of cache addresses */
> +static int action_cache_range(enum cache_action action, u32 start_addr,
> +			      int64_t size)
> +{
> +	u32 cline_size;
> +	u32 *action_reg;
> +	enum cache_type type;

Does this ever check whether start_addr and size is unaligned ?
Also, you use u32 all over the place, but size is signed-i64 ? Why?

> +	action_reg = get_action_reg_range(action);
> +	if (!action_reg)
> +		return -EINVAL;
> +	if (action == INVALIDATE_POU)
> +		type = ICACHE;
> +	else
> +		type = DCACHE;
> +
> +	/* Cache line size is minium size for the cache action */
> +	cline_size = get_cline_size(type);
> +	/* Align start address to cache line boundary */
> +	start_addr &= ~(cline_size - 1);
> +	debug("total size for cache action = %llx\n", size);
> +	do {
> +		writel(start_addr, action_reg);
> +		size -= cline_size;
> +		start_addr += cline_size;
> +	} while (size > cline_size);
> +
> +	/* Make sure cache action is effective for next memory access */
> +	dsb();
> +	isb();	/* Make sure instruction stream sees it */
> +	debug("cache action on range done\n");
> +
> +	return 0;
> +}

[...]

>  
> -#define V7M_SCB_BASE		0xE000ED00
> -#define V7M_MPU_BASE		0xE000ED90
> +/* armv7m fixed base addresses */
> +#define V7M_SCS_BASE		0xE000E000

Is all of this really used in the code ?

> +#define V7M_NVIC_BASE		(V7M_SCS_BASE + 0x0100)
> +#define V7M_SCB_BASE		(V7M_SCS_BASE + 0x0D00)
> +#define V7M_PROC_FTR_BASE	(V7M_SCS_BASE + 0x0D78)
> +#define V7M_MPU_BASE		(V7M_SCS_BASE + 0x0D90)
> +#define V7M_FPU_BASE		(V7M_SCS_BASE + 0x0F30)
> +#define V7M_CACHE_MAINT_BASE	(V7M_SCS_BASE + 0x0F50)
> +#define V7M_ACCESS_CNTL_BASE	(V7M_SCS_BASE + 0x0F90)
>  
>  #define V7M_SCB_VTOR		0x08
>  
> @@ -27,6 +34,18 @@ struct v7m_scb {
>  	uint32_t icsr;		/* Interrupt Control and State Register */
>  	uint32_t vtor;		/* Vector Table Offset Register */
>  	uint32_t aircr;		/* App Interrupt and Reset Control Register */
> +	uint32_t scr;		/* offset 0x10: System Control Register */
> +	uint32_t ccr;		/* offset 0x14: Config and Control Register */
> +	uint32_t shpr1;		/* offset 0x18: System Handler Priority Reg 1 */
> +	uint32_t shpr2;		/* offset 0x1c: System Handler Priority Reg 2 */
> +	uint32_t shpr3;		/* offset 0x20: System Handler Priority Reg 3 */
> +	uint32_t shcrs;		/* offset 0x24: System Handler Control State */
> +	uint32_t cfsr;		/* offset 0x28: Configurable Fault Status Reg */
> +	uint32_t hfsr;		/* offset 0x2C: HardFault Status Register */
> +	uint32_t res;		/* offset 0x30: reserved */
> +	uint32_t mmar;		/* offset 0x34: MemManage Fault Address Reg */
> +	uint32_t bfar;		/* offset 0x38: BusFault Address Reg */
> +	uint32_t afsr;		/* offset 0x3C: Auxiliary Fault Status Reg */
>  };
>  #define V7M_SCB				((struct v7m_scb *)V7M_SCB_BASE)
>  
> @@ -39,6 +58,9 @@ struct v7m_scb {
>  
>  #define V7M_ICSR_VECTACT_MSK		0xFF
>  
> +#define V7M_CCR_DCACHE			16
> +#define V7M_CCR_ICACHE			17
> +
>  struct v7m_mpu {
>  	uint32_t type;		/* Type Register */
>  	uint32_t ctrl;		/* Control Register */
> diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
> index 166fa9e..52b36b3 100644
> --- a/arch/arm/lib/Makefile
> +++ b/arch/arm/lib/Makefile
> @@ -55,8 +55,10 @@ endif
>  
>  obj-y	+= cache.o
>  ifndef CONFIG_ARM64
> +ifndef CONFIG_CPU_V7M
>  obj-y	+= cache-cp15.o
>  endif
> +endif
>  
>  obj-y	+= psci-dt.o
>  
> 


-- 
Best regards,
Marek Vasut


More information about the U-Boot mailing list