diff -drupN a/arch/arm/mach-sunxi/sun8i-cci.c b/arch/arm/mach-sunxi/sun8i-cci.c --- a/arch/arm/mach-sunxi/sun8i-cci.c 1970-01-01 03:00:00.000000000 +0300 +++ b/arch/arm/mach-sunxi/sun8i-cci.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,211 @@ +/* + * linux/arch/arm/mach-sunxi/sun8i-cci.c + * + * Copyright(c) 2013-2015 Allwinnertech Co., Ltd. + * http://www.allwinnertech.com + * + * Author: sunny + * + * allwinner sun9i soc platform CCI(Cache Coherent Interconnect) driver. + * this init version clone from samsung exynos platform. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Control interface register offsets */ +#define CTLR_OVERRIDE_REG 0x0 +#define SPEC_CTLR_REG 0x4 +#define SECURE_ACCESS_REG 0x8 +#define STATUS_REG 0xc +#define IMPRECISE_ERR_REG 0x10 +#define PERF_MON_CTRL_REG 0x100 + +/* Slave interface */ +#define CCI_C1_SL_IFACE(x) ((x) + 0x5000) +#define CCI_C0_SL_IFACE(x) ((x) + 0x4000) + +/* Slave interface register */ +#define SNOOP_CTLR_REG 0x0 + +/* CORE_MISC SFR */ +#define BACKBONE_SEL_REG 0x0 +#define MDMA_SHARED_CTRL 0x10 +#define SSS_SHARED_CTRL 0x20 +#define G2D_SHARED_CTRL 0x30 + +static void __iomem *cci_base; +static int cci_enabled __read_mostly; + +void enable_cci_snoops(unsigned int cluster_id) +{ + void __iomem *control_reg; + unsigned int value; + + if (!cci_enabled) + return; + + /* pr_info("sunxi cci: enable cluster[%d] snoop\n", cluster_id); */ + + if (cluster_id) + control_reg = CCI_C1_SL_IFACE(cci_base) + SNOOP_CTLR_REG; + else + control_reg = CCI_C0_SL_IFACE(cci_base) + SNOOP_CTLR_REG; + + if ((readl(control_reg) & 0x3) == 0x3) + return; + + /* Turn on CCI snoops */ + value = readl(control_reg); + value |= 0x3; + writel(value, control_reg); + dsb(); + + /* Wait for the dust to settle down */ + while (readl(cci_base + STATUS_REG) & 0x1) + ; +} + +void disable_cci_snoops(unsigned int cluster_id) +{ + void __iomem *control_reg; + unsigned int value; + + if (!cci_enabled) + return; + + if (cluster_id) + control_reg = CCI_C1_SL_IFACE(cci_base) + SNOOP_CTLR_REG; + else + control_reg = CCI_C0_SL_IFACE(cci_base) + SNOOP_CTLR_REG; + + if (!(readl(control_reg) & 0x3)) + return; + + /* Turn off CCI snoops */ + value = readl(control_reg); + value &= (~0x3); + writel(value, control_reg); + dsb(); + + /* Wait for the dust to settle down */ + while (readl(cci_base + STATUS_REG) & 0x1) + ; +} + +/* + * Use our own MPIDR accessors as the generic ones in asm/cputype.h have + * __attribute_const__ and we don't want the compiler to assume any + * constness here. + */ + +static int read_mpidr(void) +{ + unsigned int id; + asm volatile ("mrc\tp15, 0, %0, c0, c0, 5" : "=r" (id)); + return id; +} + +#if defined(CONFIG_PM) +static int cci_status[2]; + +static int get_cci_snoop_status(unsigned int cluster_id) +{ + void __iomem *control_reg; + + if (!cci_enabled) + return 0; + + if (cluster_id) + control_reg = CCI_C1_SL_IFACE(cci_base) + SNOOP_CTLR_REG; + else + control_reg = CCI_C0_SL_IFACE(cci_base) + SNOOP_CTLR_REG; + + if ((readl(control_reg) & 0x3)) + return 1; + + return 0; +} + +static int cci_suspend(void) +{ + int i; + + if (!cci_enabled) + return 0; + + for (i = 0; i < 2; i++) + cci_status[i] = get_cci_snoop_status(i); + + if (cci_status[0] && (!cci_status[1])) + disable_cci_snoops(0); + + return 0; +} + +static void cci_resume(void) +{ + unsigned int cluster_id = (read_mpidr() >> 8) & 0xf; + + if ((cluster_id != 0) && (cluster_id != 1)) + pr_err("[%s]cluster id error! cluster id %d\n", + __func__, cluster_id); + + if (cci_enabled) { + if (cci_status[cluster_id]) + enable_cci_snoops(cluster_id); + } +} + +#else +#define cci_suspend NULL +#define cci_resume NULL +#endif + +static struct syscore_ops cci_syscore_ops = { + .suspend = cci_suspend, + .resume = cci_resume, +}; + +int __init sun8i_cci_init(void) +{ + unsigned int cluster_id = (read_mpidr() >> 8) & 0xf; + struct device_node *np; + +#if defined(CONFIG_SUN8I_CCI) + cci_enabled = 1; +#endif + if (!cci_enabled) { + pr_info("sunxi cci is not supported\n"); + goto disabled; + } + + np = of_find_compatible_node(NULL, NULL, "allwinner,sunxi-cci"); + if (!np) { + pr_err("Can not find sunxi cci device tree\n"); + } + + cci_base = of_iomap(np, 0); + if (!cci_base) { + pr_err("cci mem base iomap Failed\n"); + } + of_node_put(np); + + enable_cci_snoops(cluster_id); + register_syscore_ops(&cci_syscore_ops); + +disabled: + return 0; +}