diff options
Diffstat (limited to 'drivers/soc')
50 files changed, 1696 insertions, 787 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index d097d070f579..f357c6c659d2 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -22,7 +22,6 @@ source "drivers/soc/ti/Kconfig" source "drivers/soc/ux500/Kconfig" source "drivers/soc/versatile/Kconfig" source "drivers/soc/xilinx/Kconfig" -source "drivers/soc/zte/Kconfig" source "drivers/soc/kendryte/Kconfig" endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 699b758d28e4..9bceb12b291d 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -28,5 +28,4 @@ obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_PLAT_VERSATILE) += versatile/ obj-y += xilinx/ -obj-$(CONFIG_ARCH_ZX) += zte/ obj-$(CONFIG_SOC_KENDRYTE) += kendryte/ diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index 682ba0eb4eba..20acac6342ef 100644 --- a/drivers/soc/aspeed/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c @@ -11,6 +11,7 @@ */ #include <linux/bitops.h> +#include <linux/clk.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/kfifo.h> @@ -67,6 +68,7 @@ struct aspeed_lpc_snoop_channel { struct aspeed_lpc_snoop { struct regmap *regmap; int irq; + struct clk *clk; struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS]; }; @@ -282,22 +284,42 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev) return -ENODEV; } + lpc_snoop->clk = devm_clk_get(dev, NULL); + if (IS_ERR(lpc_snoop->clk)) { + rc = PTR_ERR(lpc_snoop->clk); + if (rc != -EPROBE_DEFER) + dev_err(dev, "couldn't get clock\n"); + return rc; + } + rc = clk_prepare_enable(lpc_snoop->clk); + if (rc) { + dev_err(dev, "couldn't enable clock\n"); + return rc; + } + rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev); if (rc) - return rc; + goto err; rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port); if (rc) - return rc; + goto err; /* Configuration of 2nd snoop channel port is optional */ if (of_property_read_u32_index(dev->of_node, "snoop-ports", 1, &port) == 0) { rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port); - if (rc) + if (rc) { aspeed_lpc_disable_snoop(lpc_snoop, 0); + goto err; + } } + return 0; + +err: + clk_disable_unprepare(lpc_snoop->clk); + return rc; } @@ -309,6 +331,8 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev) aspeed_lpc_disable_snoop(lpc_snoop, 0); aspeed_lpc_disable_snoop(lpc_snoop, 1); + clk_disable_unprepare(lpc_snoop->clk); + return 0; } diff --git a/drivers/soc/aspeed/aspeed-socinfo.c b/drivers/soc/aspeed/aspeed-socinfo.c index 773930e0cb10..e3215f826d17 100644 --- a/drivers/soc/aspeed/aspeed-socinfo.c +++ b/drivers/soc/aspeed/aspeed-socinfo.c @@ -25,6 +25,7 @@ static struct { /* AST2600 */ { "AST2600", 0x05000303 }, { "AST2620", 0x05010203 }, + { "AST2605", 0x05030103 }, }; static const char *siliconid_to_name(u32 siliconid) @@ -43,14 +44,30 @@ static const char *siliconid_to_name(u32 siliconid) static const char *siliconid_to_rev(u32 siliconid) { unsigned int rev = (siliconid >> 16) & 0xff; - - switch (rev) { - case 0: - return "A0"; - case 1: - return "A1"; - case 3: - return "A2"; + unsigned int gen = (siliconid >> 24) & 0xff; + + if (gen < 0x5) { + /* AST2500 and below */ + switch (rev) { + case 0: + return "A0"; + case 1: + return "A1"; + case 3: + return "A2"; + } + } else { + /* AST2600 */ + switch (rev) { + case 0: + return "A0"; + case 1: + return "A1"; + case 2: + return "A2"; + case 3: + return "A3"; + } } return "??"; diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c index c4472b68b7c2..a490ad7e090f 100644 --- a/drivers/soc/atmel/soc.c +++ b/drivers/soc/atmel/soc.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Atmel * * Alexandre Belloni <alexandre.belloni@free-electrons.com * Boris Brezillon <boris.brezillon@free-electrons.com - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * */ #define pr_fmt(fmt) "AT91: " fmt @@ -25,137 +21,218 @@ #define AT91_DBGU_EXID 0x44 #define AT91_CHIPID_CIDR 0x00 #define AT91_CHIPID_EXID 0x04 -#define AT91_CIDR_VERSION(x) ((x) & 0x1f) +#define AT91_CIDR_VERSION(x, m) ((x) & (m)) +#define AT91_CIDR_VERSION_MASK GENMASK(4, 0) +#define AT91_CIDR_VERSION_MASK_SAMA7G5 GENMASK(3, 0) #define AT91_CIDR_EXT BIT(31) -#define AT91_CIDR_MATCH_MASK 0x7fffffe0 +#define AT91_CIDR_MATCH_MASK GENMASK(30, 5) +#define AT91_CIDR_MASK_SAMA7G5 GENMASK(27, 5) -static const struct at91_soc __initconst socs[] = { +static const struct at91_soc socs[] __initconst = { #ifdef CONFIG_SOC_AT91RM9200 - AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"), + AT91_SOC(AT91RM9200_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91rm9200 BGA", "at91rm9200"), #endif #ifdef CONFIG_SOC_AT91SAM9 - AT91_SOC(AT91SAM9260_CIDR_MATCH, 0, "at91sam9260", NULL), - AT91_SOC(AT91SAM9261_CIDR_MATCH, 0, "at91sam9261", NULL), - AT91_SOC(AT91SAM9263_CIDR_MATCH, 0, "at91sam9263", NULL), - AT91_SOC(AT91SAM9G20_CIDR_MATCH, 0, "at91sam9g20", NULL), - AT91_SOC(AT91SAM9RL64_CIDR_MATCH, 0, "at91sam9rl64", NULL), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M11_EXID_MATCH, + AT91_SOC(AT91SAM9260_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9260", NULL), + AT91_SOC(AT91SAM9261_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9261", NULL), + AT91_SOC(AT91SAM9263_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9263", NULL), + AT91_SOC(AT91SAM9G20_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9g20", NULL), + AT91_SOC(AT91SAM9RL64_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9rl64", NULL), + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9M11_EXID_MATCH, "at91sam9m11", "at91sam9g45"), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M10_EXID_MATCH, + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9M10_EXID_MATCH, "at91sam9m10", "at91sam9g45"), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G46_EXID_MATCH, + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9G46_EXID_MATCH, "at91sam9g46", "at91sam9g45"), - AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G45_EXID_MATCH, + AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9G45_EXID_MATCH, "at91sam9g45", "at91sam9g45"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G15_EXID_MATCH, + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9G15_EXID_MATCH, "at91sam9g15", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G35_EXID_MATCH, + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9G35_EXID_MATCH, "at91sam9g35", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X35_EXID_MATCH, + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9X35_EXID_MATCH, "at91sam9x35", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G25_EXID_MATCH, + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9G25_EXID_MATCH, "at91sam9g25", "at91sam9x5"), - AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X25_EXID_MATCH, + AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9X25_EXID_MATCH, "at91sam9x25", "at91sam9x5"), - AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN12_EXID_MATCH, + AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9CN12_EXID_MATCH, "at91sam9cn12", "at91sam9n12"), - AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9N12_EXID_MATCH, + AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9N12_EXID_MATCH, "at91sam9n12", "at91sam9n12"), - AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN11_EXID_MATCH, + AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, AT91SAM9CN11_EXID_MATCH, "at91sam9cn11", "at91sam9n12"), - AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), - AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), - AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), + AT91_SOC(AT91SAM9XE128_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9xe128", "at91sam9xe128"), + AT91_SOC(AT91SAM9XE256_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9xe256", "at91sam9xe256"), + AT91_SOC(AT91SAM9XE512_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, 0, "at91sam9xe512", "at91sam9xe512"), #endif #ifdef CONFIG_SOC_SAM9X60 - AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_EXID_MATCH, "sam9x60", "sam9x60"), + AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH, + "sam9x60", "sam9x60"), AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D5M_EXID_MATCH, + AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH, "sam9x60 64MiB DDR2 SiP", "sam9x60"), AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D1G_EXID_MATCH, + AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH, "sam9x60 128MiB DDR2 SiP", "sam9x60"), AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D6K_EXID_MATCH, + AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH, "sam9x60 8MiB SDRAM SiP", "sam9x60"), #endif #ifdef CONFIG_SOC_SAMA5 - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D21CU_EXID_MATCH, "sama5d21", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D22CU_EXID_MATCH, "sama5d22", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D225C_D1M_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D225C_D1M_EXID_MATCH, "sama5d225c 16MiB SiP", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D23CU_EXID_MATCH, "sama5d23", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D24CX_EXID_MATCH, "sama5d24", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D24CU_EXID_MATCH, "sama5d24", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D26CU_EXID_MATCH, "sama5d26", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D27CU_EXID_MATCH, "sama5d27", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D27CN_EXID_MATCH, "sama5d27", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_D1G_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D27C_D1G_EXID_MATCH, "sama5d27c 128MiB SiP", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_D5M_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D27C_D5M_EXID_MATCH, "sama5d27c 64MiB SiP", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD1G_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D27C_LD1G_EXID_MATCH, "sama5d27c 128MiB LPDDR2 SiP", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD2G_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D27C_LD2G_EXID_MATCH, "sama5d27c 256MiB LPDDR2 SiP", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D28CU_EXID_MATCH, "sama5d28", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D28CN_EXID_MATCH, "sama5d28", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_D1G_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D28C_D1G_EXID_MATCH, "sama5d28c 128MiB SiP", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD1G_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D28C_LD1G_EXID_MATCH, "sama5d28c 128MiB LPDDR2 SiP", "sama5d2"), - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD2G_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D28C_LD2G_EXID_MATCH, "sama5d28c 256MiB LPDDR2 SiP", "sama5d2"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, + AT91_SOC(SAMA5D3_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D31_EXID_MATCH, "sama5d31", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, + AT91_SOC(SAMA5D3_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D33_EXID_MATCH, "sama5d33", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D34_EXID_MATCH, + AT91_SOC(SAMA5D3_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D34_EXID_MATCH, "sama5d34", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D35_EXID_MATCH, + AT91_SOC(SAMA5D3_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D35_EXID_MATCH, "sama5d35", "sama5d3"), - AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D36_EXID_MATCH, + AT91_SOC(SAMA5D3_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D36_EXID_MATCH, "sama5d36", "sama5d3"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D41_EXID_MATCH, + AT91_SOC(SAMA5D4_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D41_EXID_MATCH, "sama5d41", "sama5d4"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D42_EXID_MATCH, + AT91_SOC(SAMA5D4_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D42_EXID_MATCH, "sama5d42", "sama5d4"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D43_EXID_MATCH, + AT91_SOC(SAMA5D4_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D43_EXID_MATCH, "sama5d43", "sama5d4"), - AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D44_EXID_MATCH, + AT91_SOC(SAMA5D4_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMA5D44_EXID_MATCH, "sama5d44", "sama5d4"), #endif #ifdef CONFIG_SOC_SAMV7 - AT91_SOC(SAME70Q21_CIDR_MATCH, SAME70Q21_EXID_MATCH, + AT91_SOC(SAME70Q21_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAME70Q21_EXID_MATCH, "same70q21", "same7"), - AT91_SOC(SAME70Q20_CIDR_MATCH, SAME70Q20_EXID_MATCH, + AT91_SOC(SAME70Q20_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAME70Q20_EXID_MATCH, "same70q20", "same7"), - AT91_SOC(SAME70Q19_CIDR_MATCH, SAME70Q19_EXID_MATCH, + AT91_SOC(SAME70Q19_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAME70Q19_EXID_MATCH, "same70q19", "same7"), - AT91_SOC(SAMS70Q21_CIDR_MATCH, SAMS70Q21_EXID_MATCH, + AT91_SOC(SAMS70Q21_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMS70Q21_EXID_MATCH, "sams70q21", "sams7"), - AT91_SOC(SAMS70Q20_CIDR_MATCH, SAMS70Q20_EXID_MATCH, + AT91_SOC(SAMS70Q20_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMS70Q20_EXID_MATCH, "sams70q20", "sams7"), - AT91_SOC(SAMS70Q19_CIDR_MATCH, SAMS70Q19_EXID_MATCH, + AT91_SOC(SAMS70Q19_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMS70Q19_EXID_MATCH, "sams70q19", "sams7"), - AT91_SOC(SAMV71Q21_CIDR_MATCH, SAMV71Q21_EXID_MATCH, + AT91_SOC(SAMV71Q21_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMV71Q21_EXID_MATCH, "samv71q21", "samv7"), - AT91_SOC(SAMV71Q20_CIDR_MATCH, SAMV71Q20_EXID_MATCH, + AT91_SOC(SAMV71Q20_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMV71Q20_EXID_MATCH, "samv71q20", "samv7"), - AT91_SOC(SAMV71Q19_CIDR_MATCH, SAMV71Q19_EXID_MATCH, + AT91_SOC(SAMV71Q19_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMV71Q19_EXID_MATCH, "samv71q19", "samv7"), - AT91_SOC(SAMV70Q20_CIDR_MATCH, SAMV70Q20_EXID_MATCH, + AT91_SOC(SAMV70Q20_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMV70Q20_EXID_MATCH, "samv70q20", "samv7"), - AT91_SOC(SAMV70Q19_CIDR_MATCH, SAMV70Q19_EXID_MATCH, + AT91_SOC(SAMV70Q19_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAMV70Q19_EXID_MATCH, "samv70q19", "samv7"), #endif +#ifdef CONFIG_SOC_SAMA7 + AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G51_EXID_MATCH, + "sama7g51", "sama7g5"), + AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G52_EXID_MATCH, + "sama7g52", "sama7g5"), + AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G53_EXID_MATCH, + "sama7g53", "sama7g5"), + AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_EXID_MATCH, + "sama7g54", "sama7g5"), +#endif { /* sentinel */ }, }; @@ -191,8 +268,13 @@ static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid) { struct device_node *np; void __iomem *regs; + static const struct of_device_id chipids[] = { + { .compatible = "atmel,sama5d2-chipid" }, + { .compatible = "microchip,sama7g5-chipid" }, + { }, + }; - np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid"); + np = of_find_matching_node(NULL, chipids); if (!np) return -ENODEV; @@ -235,7 +317,7 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs) } for (soc = socs; soc->name; soc++) { - if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK)) + if (soc->cidr_match != (cidr & soc->cidr_mask)) continue; if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid) @@ -254,7 +336,7 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs) soc_dev_attr->family = soc->family; soc_dev_attr->soc_id = soc->name; soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", - AT91_CIDR_VERSION(cidr)); + AT91_CIDR_VERSION(cidr, soc->version_mask)); soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { kfree(soc_dev_attr->revision); @@ -266,13 +348,27 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs) if (soc->family) pr_info("Detected SoC family: %s\n", soc->family); pr_info("Detected SoC: %s, revision %X\n", soc->name, - AT91_CIDR_VERSION(cidr)); + AT91_CIDR_VERSION(cidr, soc->version_mask)); return soc_dev; } +static const struct of_device_id at91_soc_allowed_list[] __initconst = { + { .compatible = "atmel,at91rm9200", }, + { .compatible = "atmel,at91sam9", }, + { .compatible = "atmel,sama5", }, + { .compatible = "atmel,samv7", }, + { .compatible = "microchip,sama7g5", }, + { } +}; + static int __init atmel_soc_device_init(void) { + struct device_node *np = of_find_node_by_path("/"); + + if (!of_match_node(at91_soc_allowed_list, np)) + return 0; + at91_soc_init(socs); return 0; diff --git a/drivers/soc/atmel/soc.h b/drivers/soc/atmel/soc.h index 5849846a69d6..c3eb3c8f0834 100644 --- a/drivers/soc/atmel/soc.h +++ b/drivers/soc/atmel/soc.h @@ -1,12 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Atmel * * Boris Brezillon <boris.brezillon@free-electrons.com - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * */ #ifndef __AT91_SOC_H @@ -16,14 +12,19 @@ struct at91_soc { u32 cidr_match; + u32 cidr_mask; + u32 version_mask; u32 exid_match; const char *name; const char *family; }; -#define AT91_SOC(__cidr, __exid, __name, __family) \ +#define AT91_SOC(__cidr, __cidr_mask, __version_mask, __exid, \ + __name, __family) \ { \ .cidr_match = (__cidr), \ + .cidr_mask = (__cidr_mask), \ + .version_mask = (__version_mask), \ .exid_match = (__exid), \ .name = (__name), \ .family = (__family), \ @@ -43,6 +44,7 @@ at91_soc_init(const struct at91_soc *socs); #define AT91SAM9X5_CIDR_MATCH 0x019a05a0 #define AT91SAM9N12_CIDR_MATCH 0x019a07a0 #define SAM9X60_CIDR_MATCH 0x019b35a0 +#define SAMA7G5_CIDR_MATCH 0x00162100 #define AT91SAM9M11_EXID_MATCH 0x00000001 #define AT91SAM9M10_EXID_MATCH 0x00000002 @@ -64,6 +66,11 @@ at91_soc_init(const struct at91_soc *socs); #define SAM9X60_D1G_EXID_MATCH 0x00000010 #define SAM9X60_D6K_EXID_MATCH 0x00000011 +#define SAMA7G51_EXID_MATCH 0x3 +#define SAMA7G52_EXID_MATCH 0x2 +#define SAMA7G53_EXID_MATCH 0x1 +#define SAMA7G54_EXID_MATCH 0x0 + #define AT91SAM9XE128_CIDR_MATCH 0x329973a0 #define AT91SAM9XE256_CIDR_MATCH 0x329a93a0 #define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0 diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile index 7bc90e0bd773..0f0efa28d92b 100644 --- a/drivers/soc/bcm/Makefile +++ b/drivers/soc/bcm/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o -obj-$(CONFIG_SOC_BCM63XX) += bcm63xx/ +obj-y += bcm63xx/ obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/ diff --git a/drivers/soc/bcm/bcm63xx/Kconfig b/drivers/soc/bcm/bcm63xx/Kconfig index 16f648a6c70a..9e501c8ac5ce 100644 --- a/drivers/soc/bcm/bcm63xx/Kconfig +++ b/drivers/soc/bcm/bcm63xx/Kconfig @@ -10,3 +10,12 @@ config BCM63XX_POWER BCM6318, BCM6328, BCM6362 and BCM63268 SoCs. endif # SOC_BCM63XX + +config BCM_PMB + bool "Broadcom PMB (Power Management Bus) driver" + depends on ARCH_BCM4908 || (COMPILE_TEST && OF) + default ARCH_BCM4908 + select PM_GENERIC_DOMAINS if PM + help + This enables support for the Broadcom's PMB (Power Management Bus) that + is used for disabling and enabling SoC devices. diff --git a/drivers/soc/bcm/bcm63xx/Makefile b/drivers/soc/bcm/bcm63xx/Makefile index 0710d5e018cc..557eed3d67bd 100644 --- a/drivers/soc/bcm/bcm63xx/Makefile +++ b/drivers/soc/bcm/bcm63xx/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o +obj-$(CONFIG_BCM_PMB) += bcm-pmb.o diff --git a/drivers/soc/bcm/bcm63xx/bcm-pmb.c b/drivers/soc/bcm/bcm63xx/bcm-pmb.c new file mode 100644 index 000000000000..c223023dc64f --- /dev/null +++ b/drivers/soc/bcm/bcm63xx/bcm-pmb.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2013 Broadcom + * Copyright (C) 2020 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> + */ + +#include <dt-bindings/soc/bcm-pmb.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/reset/bcm63xx_pmb.h> + +#define BPCM_ID_REG 0x00 +#define BPCM_CAPABILITIES 0x04 +#define BPCM_CAP_NUM_ZONES 0x000000ff +#define BPCM_CAP_SR_REG_BITS 0x0000ff00 +#define BPCM_CAP_PLLTYPE 0x00030000 +#define BPCM_CAP_UBUS 0x00080000 +#define BPCM_CONTROL 0x08 +#define BPCM_STATUS 0x0c +#define BPCM_ROSC_CONTROL 0x10 +#define BPCM_ROSC_THRESH_H 0x14 +#define BPCM_ROSC_THRESHOLD_BCM6838 0x14 +#define BPCM_ROSC_THRESH_S 0x18 +#define BPCM_ROSC_COUNT_BCM6838 0x18 +#define BPCM_ROSC_COUNT 0x1c +#define BPCM_PWD_CONTROL_BCM6838 0x1c +#define BPCM_PWD_CONTROL 0x20 +#define BPCM_SR_CONTROL_BCM6838 0x20 +#define BPCM_PWD_ACCUM_CONTROL 0x24 +#define BPCM_SR_CONTROL 0x28 +#define BPCM_GLOBAL_CONTROL 0x2c +#define BPCM_MISC_CONTROL 0x30 +#define BPCM_MISC_CONTROL2 0x34 +#define BPCM_SGPHY_CNTL 0x38 +#define BPCM_SGPHY_STATUS 0x3c +#define BPCM_ZONE0 0x40 +#define BPCM_ZONE_CONTROL 0x00 +#define BPCM_ZONE_CONTROL_MANUAL_CLK_EN 0x00000001 +#define BPCM_ZONE_CONTROL_MANUAL_RESET_CTL 0x00000002 +#define BPCM_ZONE_CONTROL_FREQ_SCALE_USED 0x00000004 /* R/O */ +#define BPCM_ZONE_CONTROL_DPG_CAPABLE 0x00000008 /* R/O */ +#define BPCM_ZONE_CONTROL_MANUAL_MEM_PWR 0x00000030 +#define BPCM_ZONE_CONTROL_MANUAL_ISO_CTL 0x00000040 +#define BPCM_ZONE_CONTROL_MANUAL_CTL 0x00000080 +#define BPCM_ZONE_CONTROL_DPG_CTL_EN 0x00000100 +#define BPCM_ZONE_CONTROL_PWR_DN_REQ 0x00000200 +#define BPCM_ZONE_CONTROL_PWR_UP_REQ 0x00000400 +#define BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN 0x00000800 +#define BPCM_ZONE_CONTROL_BLK_RESET_ASSERT 0x00001000 +#define BPCM_ZONE_CONTROL_MEM_STBY 0x00002000 +#define BPCM_ZONE_CONTROL_RESERVED 0x0007c000 +#define BPCM_ZONE_CONTROL_PWR_CNTL_STATE 0x00f80000 +#define BPCM_ZONE_CONTROL_FREQ_SCALAR_DYN_SEL 0x01000000 /* R/O */ +#define BPCM_ZONE_CONTROL_PWR_OFF_STATE 0x02000000 /* R/O */ +#define BPCM_ZONE_CONTROL_PWR_ON_STATE 0x04000000 /* R/O */ +#define BPCM_ZONE_CONTROL_PWR_GOOD 0x08000000 /* R/O */ +#define BPCM_ZONE_CONTROL_DPG_PWR_STATE 0x10000000 /* R/O */ +#define BPCM_ZONE_CONTROL_MEM_PWR_STATE 0x20000000 /* R/O */ +#define BPCM_ZONE_CONTROL_ISO_STATE 0x40000000 /* R/O */ +#define BPCM_ZONE_CONTROL_RESET_STATE 0x80000000 /* R/O */ +#define BPCM_ZONE_CONFIG1 0x04 +#define BPCM_ZONE_CONFIG2 0x08 +#define BPCM_ZONE_FREQ_SCALAR_CONTROL 0x0c +#define BPCM_ZONE_SIZE 0x10 + +struct bcm_pmb { + struct device *dev; + void __iomem *base; + spinlock_t lock; + bool little_endian; + struct genpd_onecell_data genpd_onecell_data; +}; + +struct bcm_pmb_pd_data { + const char * const name; + int id; + u8 bus; + u8 device; +}; + +struct bcm_pmb_pm_domain { + struct bcm_pmb *pmb; + const struct bcm_pmb_pd_data *data; + struct generic_pm_domain genpd; +}; + +static int bcm_pmb_bpcm_read(struct bcm_pmb *pmb, int bus, u8 device, + int offset, u32 *val) +{ + void __iomem *base = pmb->base + bus * 0x20; + unsigned long flags; + int err; + + spin_lock_irqsave(&pmb->lock, flags); + err = bpcm_rd(base, device, offset, val); + spin_unlock_irqrestore(&pmb->lock, flags); + + if (!err) + *val = pmb->little_endian ? le32_to_cpu(*val) : be32_to_cpu(*val); + + return err; +} + +static int bcm_pmb_bpcm_write(struct bcm_pmb *pmb, int bus, u8 device, + int offset, u32 val) +{ + void __iomem *base = pmb->base + bus * 0x20; + unsigned long flags; + int err; + + val = pmb->little_endian ? cpu_to_le32(val) : cpu_to_be32(val); + + spin_lock_irqsave(&pmb->lock, flags); + err = bpcm_wr(base, device, offset, val); + spin_unlock_irqrestore(&pmb->lock, flags); + + return err; +} + +static int bcm_pmb_power_off_zone(struct bcm_pmb *pmb, int bus, u8 device, + int zone) +{ + int offset; + u32 val; + int err; + + offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL; + + err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val); + if (err) + return err; + + val |= BPCM_ZONE_CONTROL_PWR_DN_REQ; + val &= ~BPCM_ZONE_CONTROL_PWR_UP_REQ; + + err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val); + + return err; +} + +static int bcm_pmb_power_on_zone(struct bcm_pmb *pmb, int bus, u8 device, + int zone) +{ + int offset; + u32 val; + int err; + + offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL; + + err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val); + if (err) + return err; + + if (!(val & BPCM_ZONE_CONTROL_PWR_ON_STATE)) { + val &= ~BPCM_ZONE_CONTROL_PWR_DN_REQ; + val |= BPCM_ZONE_CONTROL_DPG_CTL_EN; + val |= BPCM_ZONE_CONTROL_PWR_UP_REQ; + val |= BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN; + val |= BPCM_ZONE_CONTROL_BLK_RESET_ASSERT; + + err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val); + } + + return err; +} + +static int bcm_pmb_power_off_device(struct bcm_pmb *pmb, int bus, u8 device) +{ + int offset; + u32 val; + int err; + + /* Entire device can be powered off by powering off the 0th zone */ + offset = BPCM_ZONE0 + BPCM_ZONE_CONTROL; + + err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val); + if (err) + return err; + + if (!(val & BPCM_ZONE_CONTROL_PWR_OFF_STATE)) { + val = BPCM_ZONE_CONTROL_PWR_DN_REQ; + + err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val); + } + + return err; +} + +static int bcm_pmb_power_on_device(struct bcm_pmb *pmb, int bus, u8 device) +{ + u32 val; + int err; + int i; + + err = bcm_pmb_bpcm_read(pmb, bus, device, BPCM_CAPABILITIES, &val); + if (err) + return err; + + for (i = 0; i < (val & BPCM_CAP_NUM_ZONES); i++) { + err = bcm_pmb_power_on_zone(pmb, bus, device, i); + if (err) + return err; + } + + return err; +} + +static int bcm_pmb_power_on(struct generic_pm_domain *genpd) +{ + struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd); + const struct bcm_pmb_pd_data *data = pd->data; + struct bcm_pmb *pmb = pd->pmb; + + switch (data->id) { + case BCM_PMB_PCIE0: + case BCM_PMB_PCIE1: + case BCM_PMB_PCIE2: + return bcm_pmb_power_on_zone(pmb, data->bus, data->device, 0); + case BCM_PMB_HOST_USB: + return bcm_pmb_power_on_device(pmb, data->bus, data->device); + default: + dev_err(pmb->dev, "unsupported device id: %d\n", data->id); + return -EINVAL; + } +} + +static int bcm_pmb_power_off(struct generic_pm_domain *genpd) +{ + struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd); + const struct bcm_pmb_pd_data *data = pd->data; + struct bcm_pmb *pmb = pd->pmb; + + switch (data->id) { + case BCM_PMB_PCIE0: + case BCM_PMB_PCIE1: + case BCM_PMB_PCIE2: + return bcm_pmb_power_off_zone(pmb, data->bus, data->device, 0); + case BCM_PMB_HOST_USB: + return bcm_pmb_power_off_device(pmb, data->bus, data->device); + default: + dev_err(pmb->dev, "unsupported device id: %d\n", data->id); + return -EINVAL; + } +} + +static int bcm_pmb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct bcm_pmb_pd_data *table; + const struct bcm_pmb_pd_data *e; + struct resource *res; + struct bcm_pmb *pmb; + int max_id; + int err; + + pmb = devm_kzalloc(dev, sizeof(*pmb), GFP_KERNEL); + if (!pmb) + return -ENOMEM; + + pmb->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pmb->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmb->base)) + return PTR_ERR(pmb->base); + + spin_lock_init(&pmb->lock); + + pmb->little_endian = !of_device_is_big_endian(dev->of_node); + + table = of_device_get_match_data(dev); + if (!table) + return -EINVAL; + + max_id = 0; + for (e = table; e->name; e++) + max_id = max(max_id, e->id); + + pmb->genpd_onecell_data.num_domains = max_id + 1; + pmb->genpd_onecell_data.domains = + devm_kcalloc(dev, pmb->genpd_onecell_data.num_domains, + sizeof(struct generic_pm_domain *), GFP_KERNEL); + if (!pmb->genpd_onecell_data.domains) + return -ENOMEM; + + for (e = table; e->name; e++) { + struct bcm_pmb_pm_domain *pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + + pd->pmb = pmb; + pd->data = e; + pd->genpd.name = e->name; + pd->genpd.power_on = bcm_pmb_power_on; + pd->genpd.power_off = bcm_pmb_power_off; + + pm_genpd_init(&pd->genpd, NULL, true); + pmb->genpd_onecell_data.domains[e->id] = &pd->genpd; + } + + err = of_genpd_add_provider_onecell(dev->of_node, &pmb->genpd_onecell_data); + if (err) { + dev_err(dev, "failed to add genpd provider: %d\n", err); + return err; + } + + return 0; +} + +static const struct bcm_pmb_pd_data bcm_pmb_bcm4908_data[] = { + { .name = "pcie2", .id = BCM_PMB_PCIE2, .bus = 0, .device = 2, }, + { .name = "pcie0", .id = BCM_PMB_PCIE0, .bus = 1, .device = 14, }, + { .name = "pcie1", .id = BCM_PMB_PCIE1, .bus = 1, .device = 15, }, + { .name = "usb", .id = BCM_PMB_HOST_USB, .bus = 1, .device = 17, }, + { }, +}; + +static const struct of_device_id bcm_pmb_of_match[] = { + { .compatible = "brcm,bcm4908-pmb", .data = &bcm_pmb_bcm4908_data, }, + { }, +}; + +static struct platform_driver bcm_pmb_driver = { + .driver = { + .name = "bcm-pmb", + .of_match_table = bcm_pmb_of_match, + }, + .probe = bcm_pmb_probe, +}; + +builtin_platform_driver(bcm_pmb_driver); diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c index d33a383701dd..e87dfc6660f3 100644 --- a/drivers/soc/bcm/brcmstb/common.c +++ b/drivers/soc/bcm/brcmstb/common.c @@ -11,8 +11,6 @@ #include <linux/soc/brcmstb/brcmstb.h> #include <linux/sys_soc.h> -#include <soc/brcmstb/common.h> - static u32 family_id; static u32 product_id; @@ -21,21 +19,6 @@ static const struct of_device_id brcmstb_machine_match[] = { { } }; -bool soc_is_brcmstb(void) -{ - const struct of_device_id *match; - struct device_node *root; - - root = of_find_node_by_path("/"); - if (!root) - return false; - - match = of_match_node(brcmstb_machine_match, root); - of_node_put(root); - - return match != NULL; -} - u32 brcmstb_get_family_id(void) { return family_id; diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c index 497a7e0fd027..654e9246ce6b 100644 --- a/drivers/soc/fsl/qe/qe_common.c +++ b/drivers/soc/fsl/qe/qe_common.c @@ -27,7 +27,7 @@ static struct gen_pool *muram_pool; static spinlock_t cpm_muram_lock; -static u8 __iomem *muram_vbase; +static void __iomem *muram_vbase; static phys_addr_t muram_pbase; struct muram_block { @@ -223,9 +223,9 @@ void __iomem *cpm_muram_addr(unsigned long offset) } EXPORT_SYMBOL(cpm_muram_addr); -unsigned long cpm_muram_offset(void __iomem *addr) +unsigned long cpm_muram_offset(const void __iomem *addr) { - return addr - (void __iomem *)muram_vbase; + return addr - muram_vbase; } EXPORT_SYMBOL(cpm_muram_offset); @@ -235,6 +235,18 @@ EXPORT_SYMBOL(cpm_muram_offset); */ dma_addr_t cpm_muram_dma(void __iomem *addr) { - return muram_pbase + ((u8 __iomem *)addr - muram_vbase); + return muram_pbase + (addr - muram_vbase); } EXPORT_SYMBOL(cpm_muram_dma); + +/* + * As cpm_muram_free, but takes the virtual address rather than the + * muram offset. + */ +void cpm_muram_free_addr(const void __iomem *addr) +{ + if (!addr) + return; + cpm_muram_free(cpm_muram_offset(addr)); +} +EXPORT_SYMBOL(cpm_muram_free_addr); diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index a9370f4aacca..05812f8ae734 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -13,7 +13,7 @@ config SOC_IMX8M depends on ARCH_MXC || COMPILE_TEST default ARCH_MXC && ARM64 select SOC_BUS - select ARM_GIC_V3 if ARCH_MXC + select ARM_GIC_V3 if ARCH_MXC && ARCH_MULTI_V7 help If you say yes here you get support for the NXP i.MX8M family support, it will provide the SoC info like SoC family, diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c index cc57a384d74d..071e14496e4b 100644 --- a/drivers/soc/imx/soc-imx8m.c +++ b/drivers/soc/imx/soc-imx8m.c @@ -5,6 +5,8 @@ #include <linux/init.h> #include <linux/io.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> #include <linux/of_address.h> #include <linux/slab.h> #include <linux/sys_soc.h> @@ -29,7 +31,7 @@ struct imx8_soc_data { char *name; - u32 (*soc_revision)(void); + u32 (*soc_revision)(struct device *dev); }; static u64 soc_uid; @@ -50,7 +52,7 @@ static u32 imx8mq_soc_revision_from_atf(void) static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; }; #endif -static u32 __init imx8mq_soc_revision(void) +static u32 __init imx8mq_soc_revision(struct device *dev) { struct device_node *np; void __iomem *ocotp_base; @@ -75,9 +77,20 @@ static u32 __init imx8mq_soc_revision(void) rev = REV_B1; } - soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); - soc_uid <<= 32; - soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); + if (dev) { + int ret; + + ret = nvmem_cell_read_u64(dev, "soc_unique_id", &soc_uid); + if (ret) { + iounmap(ocotp_base); + of_node_put(np); + return ret; + } + } else { + soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); + soc_uid <<= 32; + soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); + } iounmap(ocotp_base); of_node_put(np); @@ -107,7 +120,7 @@ static void __init imx8mm_soc_uid(void) of_node_put(np); } -static u32 __init imx8mm_soc_revision(void) +static u32 __init imx8mm_soc_revision(struct device *dev) { struct device_node *np; void __iomem *anatop_base; @@ -125,7 +138,15 @@ static u32 __init imx8mm_soc_revision(void) iounmap(anatop_base); of_node_put(np); - imx8mm_soc_uid(); + if (dev) { + int ret; + + ret = nvmem_cell_read_u64(dev, "soc_unique_id", &soc_uid); + if (ret) + return ret; + } else { + imx8mm_soc_uid(); + } return rev; } @@ -150,7 +171,7 @@ static const struct imx8_soc_data imx8mp_soc_data = { .soc_revision = imx8mm_soc_revision, }; -static __maybe_unused const struct of_device_id imx8_soc_match[] = { +static __maybe_unused const struct of_device_id imx8_machine_match[] = { { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, }, { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, }, @@ -158,12 +179,20 @@ static __maybe_unused const struct of_device_id imx8_soc_match[] = { { } }; +static __maybe_unused const struct of_device_id imx8_soc_match[] = { + { .compatible = "fsl,imx8mq-soc", .data = &imx8mq_soc_data, }, + { .compatible = "fsl,imx8mm-soc", .data = &imx8mm_soc_data, }, + { .compatible = "fsl,imx8mn-soc", .data = &imx8mn_soc_data, }, + { .compatible = "fsl,imx8mp-soc", .data = &imx8mp_soc_data, }, + { } +}; + #define imx8_revision(soc_rev) \ soc_rev ? \ kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ "unknown" -static int __init imx8_soc_init(void) +static int imx8_soc_info(struct platform_device *pdev) { struct soc_device_attribute *soc_dev_attr; struct soc_device *soc_dev; @@ -182,7 +211,10 @@ static int __init imx8_soc_init(void) if (ret) goto free_soc; - id = of_match_node(imx8_soc_match, of_root); + if (pdev) + id = of_match_node(imx8_soc_match, pdev->dev.of_node); + else + id = of_match_node(imx8_machine_match, of_root); if (!id) { ret = -ENODEV; goto free_soc; @@ -191,8 +223,16 @@ static int __init imx8_soc_init(void) data = id->data; if (data) { soc_dev_attr->soc_id = data->name; - if (data->soc_revision) - soc_rev = data->soc_revision(); + if (data->soc_revision) { + if (pdev) { + soc_rev = data->soc_revision(&pdev->dev); + ret = soc_rev; + if (ret < 0) + goto free_soc; + } else { + soc_rev = data->soc_revision(NULL); + } + } } soc_dev_attr->revision = imx8_revision(soc_rev); @@ -230,4 +270,24 @@ free_soc: kfree(soc_dev_attr); return ret; } + +/* Retain device_initcall is for backward compatibility with DTS. */ +static int __init imx8_soc_init(void) +{ + if (of_find_matching_node_and_match(NULL, imx8_soc_match, NULL)) + return 0; + + return imx8_soc_info(NULL); +} device_initcall(imx8_soc_init); + +static struct platform_driver imx8_soc_info_driver = { + .probe = imx8_soc_info, + .driver = { + .name = "imx8_soc_info", + .of_match_table = imx8_soc_match, + }, +}; + +module_platform_driver(imx8_soc_info_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/litex/Kconfig b/drivers/soc/litex/Kconfig index 7c6b009b6f6c..7a7c38282e11 100644 --- a/drivers/soc/litex/Kconfig +++ b/drivers/soc/litex/Kconfig @@ -8,6 +8,7 @@ config LITEX config LITEX_SOC_CONTROLLER tristate "Enable LiteX SoC Controller driver" depends on OF || COMPILE_TEST + depends on HAS_IOMEM select LITEX help This option enables the SoC Controller Driver which verifies diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c index 1217cafdfd4d..9b0766384570 100644 --- a/drivers/soc/litex/litex_soc_ctrl.c +++ b/drivers/soc/litex/litex_soc_ctrl.c @@ -140,12 +140,13 @@ struct litex_soc_ctrl_device { void __iomem *base; }; +#ifdef CONFIG_OF static const struct of_device_id litex_soc_ctrl_of_match[] = { {.compatible = "litex,soc-controller"}, {}, }; - MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match); +#endif /* CONFIG_OF */ static int litex_soc_ctrl_probe(struct platform_device *pdev) { diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index b6908db534c2..90270f8114ed 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o +obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o diff --git a/drivers/soc/mediatek/mt8167-pm-domains.h b/drivers/soc/mediatek/mt8167-pm-domains.h new file mode 100644 index 000000000000..ad0b8dfa0527 --- /dev/null +++ b/drivers/soc/mediatek/mt8167-pm-domains.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8167_PM_DOMAINS_H +#define __SOC_MEDIATEK_MT8167_PM_DOMAINS_H + +#include "mtk-pm-domains.h" +#include <dt-bindings/power/mt8167-power.h> + +#define MT8167_PWR_STATUS_MFG_2D BIT(24) +#define MT8167_PWR_STATUS_MFG_ASYNC BIT(25) + +/* + * MT8167 power domain support + */ + +static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = { + [MT8167_POWER_DOMAIN_MM] = { + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_MM_EMI | + MT8167_TOP_AXI_PROT_EN_MCU_MM), + }, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT8167_POWER_DOMAIN_VDEC] = { + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT8167_POWER_DOMAIN_ISP] = { + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT8167_POWER_DOMAIN_MFG_ASYNC] = { + .sta_mask = MT8167_PWR_STATUS_MFG_ASYNC, + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, + .sram_pdn_bits = 0, + .sram_pdn_ack_bits = 0, + .bp_infracfg = { + BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_MCU_MFG | + MT8167_TOP_AXI_PROT_EN_MFG_EMI), + }, + }, + [MT8167_POWER_DOMAIN_MFG_2D] = { + .sta_mask = MT8167_PWR_STATUS_MFG_2D, + .ctl_offs = SPM_MFG_2D_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT8167_POWER_DOMAIN_MFG] = { + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT8167_POWER_DOMAIN_CONN] = { + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = SPM_CONN_PWR_CON, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = 0, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + .bp_infracfg = { + BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_CONN_EMI | + MT8167_TOP_AXI_PROT_EN_CONN_MCU | + MT8167_TOP_AXI_PROT_EN_MCU_CONN), + }, + }, +}; + +static const struct scpsys_soc_data mt8167_scpsys_data = { + .domains_data = scpsys_domain_data_mt8167, + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8167), + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, +}; + +#endif /* __SOC_MEDIATEK_MT8167_PM_DOMAINS_H */ + diff --git a/drivers/soc/mediatek/mt8183-pm-domains.h b/drivers/soc/mediatek/mt8183-pm-domains.h index 8d996c5d2682..aa5230e6c12f 100644 --- a/drivers/soc/mediatek/mt8183-pm-domains.h +++ b/drivers/soc/mediatek/mt8183-pm-domains.h @@ -38,6 +38,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { .ctl_offs = 0x0338, .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), + .caps = MTK_SCPD_DOMAIN_SUPPLY, }, [MT8183_POWER_DOMAIN_MFG_CORE0] = { .sta_mask = BIT(7), diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c index 280d3bd9f675..3c8e4212d941 100644 --- a/drivers/soc/mediatek/mtk-cmdq-helper.c +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -463,36 +463,4 @@ int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, } EXPORT_SYMBOL(cmdq_pkt_flush_async); -struct cmdq_flush_completion { - struct completion cmplt; - bool err; -}; - -static void cmdq_pkt_flush_cb(struct cmdq_cb_data data) -{ - struct cmdq_flush_completion *cmplt; - - cmplt = (struct cmdq_flush_completion *)data.data; - if (data.sta != CMDQ_CB_NORMAL) - cmplt->err = true; - else - cmplt->err = false; - complete(&cmplt->cmplt); -} - -int cmdq_pkt_flush(struct cmdq_pkt *pkt) -{ - struct cmdq_flush_completion cmplt; - int err; - - init_completion(&cmplt.cmplt); - err = cmdq_pkt_flush_async(pkt, cmdq_pkt_flush_cb, &cmplt); - if (err < 0) - return err; - wait_for_completion(&cmplt.cmplt); - - return cmplt.err ? -EFAULT : 0; -} -EXPORT_SYMBOL(cmdq_pkt_flush); - MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c new file mode 100644 index 000000000000..f531b119da7a --- /dev/null +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 MediaTek Inc. + */ + +#include <linux/clk.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/soc/mediatek/mtk-mmsys.h> +#include <linux/soc/mediatek/mtk-mutex.h> + +#define MT2701_MUTEX0_MOD0 0x2c +#define MT2701_MUTEX0_SOF0 0x30 + +#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) +#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) +#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) +#define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n)) +#define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n)) +#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n)) + +#define INT_MUTEX BIT(1) + +#define MT8167_MUTEX_MOD_DISP_PWM 1 +#define MT8167_MUTEX_MOD_DISP_OVL0 6 +#define MT8167_MUTEX_MOD_DISP_OVL1 7 +#define MT8167_MUTEX_MOD_DISP_RDMA0 8 +#define MT8167_MUTEX_MOD_DISP_RDMA1 9 +#define MT8167_MUTEX_MOD_DISP_WDMA0 10 +#define MT8167_MUTEX_MOD_DISP_CCORR 11 +#define MT8167_MUTEX_MOD_DISP_COLOR 12 +#define MT8167_MUTEX_MOD_DISP_AAL 13 +#define MT8167_MUTEX_MOD_DISP_GAMMA 14 +#define MT8167_MUTEX_MOD_DISP_DITHER 15 +#define MT8167_MUTEX_MOD_DISP_UFOE 16 + +#define MT8173_MUTEX_MOD_DISP_OVL0 11 +#define MT8173_MUTEX_MOD_DISP_OVL1 12 +#define MT8173_MUTEX_MOD_DISP_RDMA0 13 +#define MT8173_MUTEX_MOD_DISP_RDMA1 14 +#define MT8173_MUTEX_MOD_DISP_RDMA2 15 +#define MT8173_MUTEX_MOD_DISP_WDMA0 16 +#define MT8173_MUTEX_MOD_DISP_WDMA1 17 +#define MT8173_MUTEX_MOD_DISP_COLOR0 18 +#define MT8173_MUTEX_MOD_DISP_COLOR1 19 +#define MT8173_MUTEX_MOD_DISP_AAL 20 +#define MT8173_MUTEX_MOD_DISP_GAMMA 21 +#define MT8173_MUTEX_MOD_DISP_UFOE 22 +#define MT8173_MUTEX_MOD_DISP_PWM0 23 +#define MT8173_MUTEX_MOD_DISP_PWM1 24 +#define MT8173_MUTEX_MOD_DISP_OD 25 + +#define MT2712_MUTEX_MOD_DISP_PWM2 10 +#define MT2712_MUTEX_MOD_DISP_OVL0 11 +#define MT2712_MUTEX_MOD_DISP_OVL1 12 +#define MT2712_MUTEX_MOD_DISP_RDMA0 13 +#define MT2712_MUTEX_MOD_DISP_RDMA1 14 +#define MT2712_MUTEX_MOD_DISP_RDMA2 15 +#define MT2712_MUTEX_MOD_DISP_WDMA0 16 +#define MT2712_MUTEX_MOD_DISP_WDMA1 17 +#define MT2712_MUTEX_MOD_DISP_COLOR0 18 +#define MT2712_MUTEX_MOD_DISP_COLOR1 19 +#define MT2712_MUTEX_MOD_DISP_AAL0 20 +#define MT2712_MUTEX_MOD_DISP_UFOE 22 +#define MT2712_MUTEX_MOD_DISP_PWM0 23 +#define MT2712_MUTEX_MOD_DISP_PWM1 24 +#define MT2712_MUTEX_MOD_DISP_OD0 25 +#define MT2712_MUTEX_MOD2_DISP_AAL1 33 +#define MT2712_MUTEX_MOD2_DISP_OD1 34 + +#define MT2701_MUTEX_MOD_DISP_OVL 3 +#define MT2701_MUTEX_MOD_DISP_WDMA 6 +#define MT2701_MUTEX_MOD_DISP_COLOR 7 +#define MT2701_MUTEX_MOD_DISP_BLS 9 +#define MT2701_MUTEX_MOD_DISP_RDMA0 10 +#define MT2701_MUTEX_MOD_DISP_RDMA1 12 + +#define MT2712_MUTEX_SOF_SINGLE_MODE 0 +#define MT2712_MUTEX_SOF_DSI0 1 +#define MT2712_MUTEX_SOF_DSI1 2 +#define MT2712_MUTEX_SOF_DPI0 3 +#define MT2712_MUTEX_SOF_DPI1 4 +#define MT2712_MUTEX_SOF_DSI2 5 +#define MT2712_MUTEX_SOF_DSI3 6 +#define MT8167_MUTEX_SOF_DPI0 2 +#define MT8167_MUTEX_SOF_DPI1 3 + +struct mtk_mutex { + int id; + bool claimed; +}; + +enum mtk_mutex_sof_id { + MUTEX_SOF_SINGLE_MODE, + MUTEX_SOF_DSI0, + MUTEX_SOF_DSI1, + MUTEX_SOF_DPI0, + MUTEX_SOF_DPI1, + MUTEX_SOF_DSI2, + MUTEX_SOF_DSI3, +}; + +struct mtk_mutex_data { + const unsigned int *mutex_mod; + const unsigned int *mutex_sof; + const unsigned int mutex_mod_reg; + const unsigned int mutex_sof_reg; + const bool no_clk; +}; + +struct mtk_mutex_ctx { + struct device *dev; + struct clk *clk; + void __iomem *regs; + struct mtk_mutex mutex[10]; + const struct mtk_mutex_data *data; +}; + +static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS, + [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR, + [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL, + [DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA, +}; + +static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0, + [DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1, + [DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0, + [DDP_COMPONENT_COLOR1] = MT2712_MUTEX_MOD_DISP_COLOR1, + [DDP_COMPONENT_OD0] = MT2712_MUTEX_MOD_DISP_OD0, + [DDP_COMPONENT_OD1] = MT2712_MUTEX_MOD2_DISP_OD1, + [DDP_COMPONENT_OVL0] = MT2712_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL1] = MT2712_MUTEX_MOD_DISP_OVL1, + [DDP_COMPONENT_PWM0] = MT2712_MUTEX_MOD_DISP_PWM0, + [DDP_COMPONENT_PWM1] = MT2712_MUTEX_MOD_DISP_PWM1, + [DDP_COMPONENT_PWM2] = MT2712_MUTEX_MOD_DISP_PWM2, + [DDP_COMPONENT_RDMA0] = MT2712_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT2712_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_RDMA2] = MT2712_MUTEX_MOD_DISP_RDMA2, + [DDP_COMPONENT_UFOE] = MT2712_MUTEX_MOD_DISP_UFOE, + [DDP_COMPONENT_WDMA0] = MT2712_MUTEX_MOD_DISP_WDMA0, + [DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1, +}; + +static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT8167_MUTEX_MOD_DISP_AAL, + [DDP_COMPONENT_CCORR] = MT8167_MUTEX_MOD_DISP_CCORR, + [DDP_COMPONENT_COLOR0] = MT8167_MUTEX_MOD_DISP_COLOR, + [DDP_COMPONENT_DITHER] = MT8167_MUTEX_MOD_DISP_DITHER, + [DDP_COMPONENT_GAMMA] = MT8167_MUTEX_MOD_DISP_GAMMA, + [DDP_COMPONENT_OVL0] = MT8167_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL1] = MT8167_MUTEX_MOD_DISP_OVL1, + [DDP_COMPONENT_PWM0] = MT8167_MUTEX_MOD_DISP_PWM, + [DDP_COMPONENT_RDMA0] = MT8167_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT8167_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_UFOE] = MT8167_MUTEX_MOD_DISP_UFOE, + [DDP_COMPONENT_WDMA0] = MT8167_MUTEX_MOD_DISP_WDMA0, +}; + +static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL, + [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, + [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1, + [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA, + [DDP_COMPONENT_OD0] = MT8173_MUTEX_MOD_DISP_OD, + [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1, + [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0, + [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1, + [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2, + [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE, + [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0, + [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1, +}; + +static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = { + [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, + [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, + [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1, + [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0, + [MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1, + [MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2, + [MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3, +}; + +static const unsigned int mt8167_mutex_sof[MUTEX_SOF_DSI3 + 1] = { + [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, + [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, + [MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0, + [MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1, +}; + +static const struct mtk_mutex_data mt2701_mutex_driver_data = { + .mutex_mod = mt2701_mutex_mod, + .mutex_sof = mt2712_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, +}; + +static const struct mtk_mutex_data mt2712_mutex_driver_data = { + .mutex_mod = mt2712_mutex_mod, + .mutex_sof = mt2712_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, +}; + +static const struct mtk_mutex_data mt8167_mutex_driver_data = { + .mutex_mod = mt8167_mutex_mod, + .mutex_sof = mt8167_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, + .no_clk = true, +}; + +static const struct mtk_mutex_data mt8173_mutex_driver_data = { + .mutex_mod = mt8173_mutex_mod, + .mutex_sof = mt2712_mutex_sof, + .mutex_mod_reg = MT2701_MUTEX0_MOD0, + .mutex_sof_reg = MT2701_MUTEX0_SOF0, +}; + +struct mtk_mutex *mtk_mutex_get(struct device *dev) +{ + struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev); + int i; + + for (i = 0; i < 10; i++) + if (!mtx->mutex[i].claimed) { + mtx->mutex[i].claimed = true; + return &mtx->mutex[i]; + } + + return ERR_PTR(-EBUSY); +} +EXPORT_SYMBOL_GPL(mtk_mutex_get); + +void mtk_mutex_put(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + mutex->claimed = false; +} +EXPORT_SYMBOL_GPL(mtk_mutex_put); + +int mtk_mutex_prepare(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + return clk_prepare_enable(mtx->clk); +} +EXPORT_SYMBOL_GPL(mtk_mutex_prepare); + +void mtk_mutex_unprepare(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + clk_disable_unprepare(mtx->clk); +} +EXPORT_SYMBOL_GPL(mtk_mutex_unprepare); + +void mtk_mutex_add_comp(struct mtk_mutex *mutex, + enum mtk_ddp_comp_id id) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + unsigned int reg; + unsigned int sof_id; + unsigned int offset; + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + switch (id) { + case DDP_COMPONENT_DSI0: + sof_id = MUTEX_SOF_DSI0; + break; + case DDP_COMPONENT_DSI1: + sof_id = MUTEX_SOF_DSI0; + break; + case DDP_COMPONENT_DSI2: + sof_id = MUTEX_SOF_DSI2; + break; + case DDP_COMPONENT_DSI3: + sof_id = MUTEX_SOF_DSI3; + break; + case DDP_COMPONENT_DPI0: + sof_id = MUTEX_SOF_DPI0; + break; + case DDP_COMPONENT_DPI1: + sof_id = MUTEX_SOF_DPI1; + break; + default: + if (mtx->data->mutex_mod[id] < 32) { + offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, + mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg |= 1 << mtx->data->mutex_mod[id]; + writel_relaxed(reg, mtx->regs + offset); + } else { + offset = DISP_REG_MUTEX_MOD2(mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg |= 1 << (mtx->data->mutex_mod[id] - 32); + writel_relaxed(reg, mtx->regs + offset); + } + return; + } + + writel_relaxed(mtx->data->mutex_sof[sof_id], + mtx->regs + + DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_add_comp); + +void mtk_mutex_remove_comp(struct mtk_mutex *mutex, + enum mtk_ddp_comp_id id) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + unsigned int reg; + unsigned int offset; + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + switch (id) { + case DDP_COMPONENT_DSI0: + case DDP_COMPONENT_DSI1: + case DDP_COMPONENT_DSI2: + case DDP_COMPONENT_DSI3: + case DDP_COMPONENT_DPI0: + case DDP_COMPONENT_DPI1: + writel_relaxed(MUTEX_SOF_SINGLE_MODE, + mtx->regs + + DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, + mutex->id)); + break; + default: + if (mtx->data->mutex_mod[id] < 32) { + offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, + mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg &= ~(1 << mtx->data->mutex_mod[id]); + writel_relaxed(reg, mtx->regs + offset); + } else { + offset = DISP_REG_MUTEX_MOD2(mutex->id); + reg = readl_relaxed(mtx->regs + offset); + reg &= ~(1 << (mtx->data->mutex_mod[id] - 32)); + writel_relaxed(reg, mtx->regs + offset); + } + break; + } +} +EXPORT_SYMBOL_GPL(mtk_mutex_remove_comp); + +void mtk_mutex_enable(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_enable); + +void mtk_mutex_disable(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + writel(0, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_disable); + +void mtk_mutex_acquire(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + u32 tmp; + + writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id)); + writel(1, mtx->regs + DISP_REG_MUTEX(mutex->id)); + if (readl_poll_timeout_atomic(mtx->regs + DISP_REG_MUTEX(mutex->id), + tmp, tmp & INT_MUTEX, 1, 10000)) + pr_err("could not acquire mutex %d\n", mutex->id); +} +EXPORT_SYMBOL_GPL(mtk_mutex_acquire); + +void mtk_mutex_release(struct mtk_mutex *mutex) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + writel(0, mtx->regs + DISP_REG_MUTEX(mutex->id)); +} +EXPORT_SYMBOL_GPL(mtk_mutex_release); + +static int mtk_mutex_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_mutex_ctx *mtx; + struct resource *regs; + int i; + + mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL); + if (!mtx) + return -ENOMEM; + + for (i = 0; i < 10; i++) + mtx->mutex[i].id = i; + + mtx->data = of_device_get_match_data(dev); + + if (!mtx->data->no_clk) { + mtx->clk = devm_clk_get(dev, NULL); + if (IS_ERR(mtx->clk)) { + if (PTR_ERR(mtx->clk) != -EPROBE_DEFER) + dev_err(dev, "Failed to get clock\n"); + return PTR_ERR(mtx->clk); + } + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mtx->regs = devm_ioremap_resource(dev, regs); + if (IS_ERR(mtx->regs)) { + dev_err(dev, "Failed to map mutex registers\n"); + return PTR_ERR(mtx->regs); + } + + platform_set_drvdata(pdev, mtx); + + return 0; +} + +static int mtk_mutex_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id mutex_driver_dt_match[] = { + { .compatible = "mediatek,mt2701-disp-mutex", + .data = &mt2701_mutex_driver_data}, + { .compatible = "mediatek,mt2712-disp-mutex", + .data = &mt2712_mutex_driver_data}, + { .compatible = "mediatek,mt8167-disp-mutex", + .data = &mt8167_mutex_driver_data}, + { .compatible = "mediatek,mt8173-disp-mutex", + .data = &mt8173_mutex_driver_data}, + {}, +}; +MODULE_DEVICE_TABLE(of, mutex_driver_dt_match); + +struct platform_driver mtk_mutex_driver = { + .probe = mtk_mutex_probe, + .remove = mtk_mutex_remove, + .driver = { + .name = "mediatek-mutex", + .owner = THIS_MODULE, + .of_match_table = mutex_driver_dt_match, + }, +}; + +builtin_platform_driver(mtk_mutex_driver); diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index fb70cb3b07b3..b7f697666bdd 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -13,8 +13,10 @@ #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <linux/soc/mediatek/infracfg.h> +#include "mt8167-pm-domains.h" #include "mt8173-pm-domains.h" #include "mt8183-pm-domains.h" #include "mt8192-pm-domains.h" @@ -40,6 +42,7 @@ struct scpsys_domain { struct clk_bulk_data *subsys_clks; struct regmap *infracfg; struct regmap *smi; + struct regulator *supply; }; struct scpsys { @@ -187,6 +190,16 @@ static int scpsys_bus_protect_disable(struct scpsys_domain *pd) return _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg); } +static int scpsys_regulator_enable(struct regulator *supply) +{ + return supply ? regulator_enable(supply) : 0; +} + +static int scpsys_regulator_disable(struct regulator *supply) +{ + return supply ? regulator_disable(supply) : 0; +} + static int scpsys_power_on(struct generic_pm_domain *genpd) { struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); @@ -194,10 +207,14 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) bool tmp; int ret; - ret = clk_bulk_enable(pd->num_clks, pd->clks); + ret = scpsys_regulator_enable(pd->supply); if (ret) return ret; + ret = clk_bulk_enable(pd->num_clks, pd->clks); + if (ret) + goto err_reg; + /* subsys power on */ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); @@ -232,6 +249,8 @@ err_disable_subsys_clks: clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks); err_pwr_ack: clk_bulk_disable(pd->num_clks, pd->clks); +err_reg: + scpsys_regulator_disable(pd->supply); return ret; } @@ -267,6 +286,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) clk_bulk_disable(pd->num_clks, pd->clks); + scpsys_regulator_disable(pd->supply); + return 0; } @@ -275,6 +296,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no { const struct scpsys_domain_data *domain_data; struct scpsys_domain *pd; + struct device_node *root_node = scpsys->dev->of_node; struct property *prop; const char *clk_name; int i, ret, num_clks; @@ -307,6 +329,25 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no pd->data = domain_data; pd->scpsys = scpsys; + if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) { + /* + * Find regulator in current power domain node. + * devm_regulator_get() finds regulator in a node and its child + * node, so set of_node to current power domain node then change + * back to original node after regulator is found for current + * power domain node. + */ + scpsys->dev->of_node = node; + pd->supply = devm_regulator_get(scpsys->dev, "domain"); + scpsys->dev->of_node = root_node; + if (IS_ERR(pd->supply)) { + dev_err_probe(scpsys->dev, PTR_ERR(pd->supply), + "%pOF: failed to get power supply.\n", + node); + return ERR_CAST(pd->supply); + } + } + pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg"); if (IS_ERR(pd->infracfg)) return ERR_CAST(pd->infracfg); @@ -446,8 +487,8 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren child_pd = scpsys_add_one_domain(scpsys, child); if (IS_ERR(child_pd)) { - ret = PTR_ERR(child_pd); - dev_err(scpsys->dev, "%pOF: failed to get child domain id\n", child); + dev_err_probe(scpsys->dev, PTR_ERR(child_pd), + "%pOF: failed to get child domain id\n", child); goto err_put_node; } @@ -515,6 +556,10 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys) static const struct of_device_id scpsys_of_match[] = { { + .compatible = "mediatek,mt8167-power-controller", + .data = &mt8167_scpsys_data, + }, + { .compatible = "mediatek,mt8173-power-controller", .data = &mt8173_scpsys_data, }, diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index a2f4d8f97e05..141dc76054e6 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -7,6 +7,7 @@ #define MTK_SCPD_FWAIT_SRAM BIT(1) #define MTK_SCPD_SRAM_ISO BIT(2) #define MTK_SCPD_KEEP_DEFAULT_OFF BIT(3) +#define MTK_SCPD_DOMAIN_SUPPLY BIT(4) #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) #define SPM_VDE_PWR_CON 0x0210 @@ -14,6 +15,7 @@ #define SPM_VEN_PWR_CON 0x0230 #define SPM_ISP_PWR_CON 0x0238 #define SPM_DIS_PWR_CON 0x023c +#define SPM_CONN_PWR_CON 0x0280 #define SPM_VEN2_PWR_CON 0x0298 #define SPM_AUDIO_PWR_CON 0x029c #define SPM_MFG_2D_PWR_CON 0x02c0 diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 16b421608e9c..8403a77b59fe 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -4,6 +4,7 @@ * */ +#include <linux/bitfield.h> #include <linux/bitmap.h> #include <linux/bitops.h> #include <linux/device.h> @@ -35,6 +36,9 @@ #define CACHE_LINE_SIZE_SHIFT 6 +#define LLCC_COMMON_HW_INFO 0x00030000 +#define LLCC_MAJOR_VERSION_MASK GENMASK(31, 24) + #define LLCC_COMMON_STATUS0 0x0003000c #define LLCC_LB_CNT_MASK GENMASK(31, 28) #define LLCC_LB_CNT_SHIFT 28 @@ -47,6 +51,7 @@ #define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00 #define LLCC_TRP_PCB_ACT 0x21f04 +#define LLCC_TRP_WRSC_EN 0x21f20 #define BANK_OFFSET_STRIDE 0x80000 @@ -73,6 +78,7 @@ * then the ways assigned to this client are not flushed on power * collapse. * @activate_on_init: Activate the slice immediately after it is programmed + * @write_scid_en: Bit enables write cache support for a given scid. */ struct llcc_slice_config { u32 usecase_id; @@ -87,6 +93,7 @@ struct llcc_slice_config { bool dis_cap_alloc; bool retain_on_pc; bool activate_on_init; + bool write_scid_en; }; struct qcom_llcc_config { @@ -147,6 +154,25 @@ static const struct llcc_slice_config sm8150_data[] = { { LLCC_WRCACHE, 31, 128, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0 }, }; +static const struct llcc_slice_config sm8250_data[] = { + { LLCC_CPUSS, 1, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 }, + { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_AUDIO, 6, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, + { LLCC_CMPT, 10, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, + { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_GPU, 12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 1 }, + { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_CMPTDMA, 15, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_DISP, 16, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_VIDFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_NPU, 23, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_WLHW, 24, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_CVP, 28, 256, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_APTCM, 30, 128, 3, 0, 0x0, 0x3, 1, 0, 0, 1, 0, 0 }, + { LLCC_WRCACHE, 31, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, +}; + static const struct qcom_llcc_config sc7180_cfg = { .sct_data = sc7180_data, .size = ARRAY_SIZE(sc7180_data), @@ -164,6 +190,11 @@ static const struct qcom_llcc_config sm8150_cfg = { .size = ARRAY_SIZE(sm8150_data), }; +static const struct qcom_llcc_config sm8250_cfg = { + .sct_data = sm8250_data, + .size = ARRAY_SIZE(sm8250_data), +}; + static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER; /** @@ -413,6 +444,16 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config, return ret; } + if (drv_data->major_version == 2) { + u32 wren; + + wren = config->write_scid_en << config->slice_id; + ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_WRSC_EN, + BIT(config->slice_id), wren); + if (ret) + return ret; + } + if (config->activate_on_init) { desc.slice_id = config->slice_id; ret = llcc_slice_activate(&desc); @@ -476,6 +517,7 @@ static int qcom_llcc_probe(struct platform_device *pdev) const struct qcom_llcc_config *cfg; const struct llcc_slice_config *llcc_cfg; u32 sz; + u32 version; drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); if (!drv_data) { @@ -496,6 +538,13 @@ static int qcom_llcc_probe(struct platform_device *pdev) goto err; } + /* Extract major version of the IP */ + ret = regmap_read(drv_data->bcast_regmap, LLCC_COMMON_HW_INFO, &version); + if (ret) + goto err; + + drv_data->major_version = FIELD_GET(LLCC_MAJOR_VERSION_MASK, version); + ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, &num_banks); if (ret) @@ -559,6 +608,7 @@ static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg }, { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg }, { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg }, + { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg }, { } }; diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 7f9e9944d1ea..f1875dc31ae2 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -189,6 +189,7 @@ struct ocmem *of_get_ocmem(struct device *dev) { struct platform_device *pdev; struct device_node *devnode; + struct ocmem *ocmem; devnode = of_parse_phandle(dev->of_node, "sram", 0); if (!devnode || !devnode->parent) { @@ -202,7 +203,12 @@ struct ocmem *of_get_ocmem(struct device *dev) return ERR_PTR(-EPROBE_DEFER); } - return platform_get_drvdata(pdev); + ocmem = platform_get_drvdata(pdev); + if (!ocmem) { + dev_err(dev, "Cannot get ocmem\n"); + return ERR_PTR(-ENODEV); + } + return ocmem; } EXPORT_SYMBOL(of_get_ocmem); diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index b5840d624bc6..53acb9423bd6 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -600,6 +600,7 @@ static const struct of_device_id qmp_dt_match[] = { { .compatible = "qcom,sdm845-aoss-qmp", }, { .compatible = "qcom,sm8150-aoss-qmp", }, { .compatible = "qcom,sm8250-aoss-qmp", }, + { .compatible = "qcom,sm8350-aoss-qmp", }, {} }; MODULE_DEVICE_TABLE(of, qmp_dt_match); diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 37969dcbaf14..a84ab0d6a9d4 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -231,10 +231,9 @@ static void tcs_invalidate(struct rsc_drv *drv, int type) if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) return; - for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) { + for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0); - write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0); - } + bitmap_zero(tcs->slots, MAX_TCS_SLOTS); } @@ -364,7 +363,7 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger) enable = TCS_AMC_MODE_ENABLE; write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable); enable |= TCS_AMC_MODE_TRIGGER; - write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable); + write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable); } } @@ -443,7 +442,6 @@ static irqreturn_t tcs_tx_done(int irq, void *p) skip: /* Reclaim the TCS */ write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0); - write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0); writel_relaxed(BIT(i), drv->tcs_base + RSC_DRV_IRQ_CLEAR); spin_lock(&drv->lock); clear_bit(i, drv->tcs_in_use); @@ -476,23 +474,23 @@ skip: static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, const struct tcs_request *msg) { - u32 msgid, cmd_msgid; + u32 msgid; + u32 cmd_msgid = CMD_MSGID_LEN | CMD_MSGID_WRITE; u32 cmd_enable = 0; - u32 cmd_complete; struct tcs_cmd *cmd; int i, j; - cmd_msgid = CMD_MSGID_LEN; + /* Convert all commands to RR when the request has wait_for_compl set */ cmd_msgid |= msg->wait_for_compl ? CMD_MSGID_RESP_REQ : 0; - cmd_msgid |= CMD_MSGID_WRITE; - - cmd_complete = read_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id); for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) { cmd = &msg->cmds[i]; cmd_enable |= BIT(j); - cmd_complete |= cmd->wait << j; msgid = cmd_msgid; + /* + * Additionally, if the cmd->wait is set, make the command + * response reqd even if the overall request was fire-n-forget. + */ msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0; write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid); @@ -501,7 +499,6 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd); } - write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, cmd_complete); cmd_enable |= read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id); write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, cmd_enable); } @@ -652,7 +649,6 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate() */ write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0); - write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0); enable_tcs_irq(drv, tcs_id, true); } spin_unlock_irqrestore(&drv->lock, flags); diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 85d1207b72d7..27733b0e7fca 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -21,6 +21,8 @@ * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */ #define RPMPD_SMPA 0x61706d73 #define RPMPD_LDOA 0x616f646c +#define RPMPD_SMPB 0x62706d73 +#define RPMPD_LDOB 0x626f646c #define RPMPD_RWCX 0x78637772 #define RPMPD_RWMX 0x786d7772 #define RPMPD_RWLC 0x636c7772 @@ -184,6 +186,31 @@ static const struct rpmpd_desc msm8976_desc = { .max_state = RPM_SMD_LEVEL_TURBO_HIGH, }; +/* msm8994 RPM Power domains */ +DEFINE_RPMPD_PAIR(msm8994, vddcx, vddcx_ao, SMPA, CORNER, 1); +DEFINE_RPMPD_PAIR(msm8994, vddmx, vddmx_ao, SMPA, CORNER, 2); +/* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */ +DEFINE_RPMPD_CORNER(msm8994, vddgfx, SMPB, 2); + +DEFINE_RPMPD_VFC(msm8994, vddcx_vfc, SMPA, 1); +DEFINE_RPMPD_VFC(msm8994, vddgfx_vfc, SMPB, 2); + +static struct rpmpd *msm8994_rpmpds[] = { + [MSM8994_VDDCX] = &msm8994_vddcx, + [MSM8994_VDDCX_AO] = &msm8994_vddcx_ao, + [MSM8994_VDDCX_VFC] = &msm8994_vddcx_vfc, + [MSM8994_VDDMX] = &msm8994_vddmx, + [MSM8994_VDDMX_AO] = &msm8994_vddmx_ao, + [MSM8994_VDDGFX] = &msm8994_vddgfx, + [MSM8994_VDDGFX_VFC] = &msm8994_vddgfx_vfc, +}; + +static const struct rpmpd_desc msm8994_desc = { + .rpmpds = msm8994_rpmpds, + .num_pds = ARRAY_SIZE(msm8994_rpmpds), + .max_state = MAX_CORNER_RPMPD_STATE, +}; + /* msm8996 RPM Power domains */ DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1); DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2); @@ -302,6 +329,7 @@ static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc }, { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, + { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc }, { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 7251827bac88..cc4e0655a47b 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -732,9 +732,7 @@ qcom_smem_partition_header(struct qcom_smem *smem, header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) { - dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n", - header->magic[0], header->magic[1], - header->magic[2], header->magic[3]); + dev_err(smem->dev, "bad partition magic %4ph\n", header->magic); return NULL; } diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index d21530d24253..f6cfb79338f0 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -15,6 +15,8 @@ #include <linux/sys_soc.h> #include <linux/types.h> +#include <asm/unaligned.h> + /* * SoC version type with major number in the upper 16 bits and minor * number in the lower 16 bits. @@ -83,6 +85,11 @@ static const char *const pmic_models[] = { [23] = "PM8038", [24] = "PM8922", [25] = "PM8917", + [30] = "PM8150", + [31] = "PM8150L", + [32] = "PM8150B", + [33] = "PMK8002", + [36] = "PM8009", }; #endif /* CONFIG_DEBUG_FS */ @@ -217,23 +224,39 @@ static const struct soc_id soc_id[] = { { 250, "MSM8616" }, { 251, "MSM8992" }, { 253, "APQ8094" }, + { 290, "MDM9607" }, { 291, "APQ8096" }, + { 292, "MSM8998" }, { 293, "MSM8953" }, + { 296, "MDM8207" }, + { 297, "MDM9207" }, + { 298, "MDM9307" }, + { 299, "MDM9628" }, { 304, "APQ8053" }, { 305, "MSM8996SG" }, { 310, "MSM8996AU" }, { 311, "APQ8096AU" }, { 312, "APQ8096SG" }, + { 317, "SDM660" }, { 318, "SDM630" }, + { 319, "APQ8098" }, { 321, "SDM845" }, + { 322, "MDM9206" }, + { 324, "SDA660" }, + { 325, "SDM658" }, + { 326, "SDA658" }, + { 327, "SDA630" }, { 338, "SDM450" }, { 341, "SDA845" }, + { 345, "SDM636" }, + { 346, "SDA636" }, { 349, "SDM632" }, { 350, "SDA632" }, { 351, "SDA450" }, { 356, "SM8250" }, { 402, "IPQ6018" }, { 425, "SC7180" }, + { 455, "QRB5165" }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) @@ -264,7 +287,7 @@ static const struct file_operations qcom_ ##name## _ops = { \ } #define DEBUGFS_ADD(info, name) \ - debugfs_create_file(__stringify(name), 0400, \ + debugfs_create_file(__stringify(name), 0444, \ qcom_socinfo->dbg_root, \ info, &qcom_ ##name## _ops) @@ -286,7 +309,7 @@ static int qcom_show_pmic_model(struct seq_file *seq, void *p) if (model < 0) return -EINVAL; - if (model <= ARRAY_SIZE(pmic_models) && pmic_models[model]) + if (model < ARRAY_SIZE(pmic_models) && pmic_models[model]) seq_printf(seq, "%s\n", pmic_models[model]); else seq_printf(seq, "unknown (%d)\n", model); @@ -294,6 +317,32 @@ static int qcom_show_pmic_model(struct seq_file *seq, void *p) return 0; } +static int qcom_show_pmic_model_array(struct seq_file *seq, void *p) +{ + struct socinfo *socinfo = seq->private; + unsigned int num_pmics = le32_to_cpu(socinfo->num_pmics); + unsigned int pmic_array_offset = le32_to_cpu(socinfo->pmic_array_offset); + int i; + void *ptr = socinfo; + + ptr += pmic_array_offset; + + /* No need for bounds checking, it happened at socinfo_debugfs_init */ + for (i = 0; i < num_pmics; i++) { + unsigned int model = SOCINFO_MINOR(get_unaligned_le32(ptr + 2 * i * sizeof(u32))); + unsigned int die_rev = get_unaligned_le32(ptr + (2 * i + 1) * sizeof(u32)); + + if (model < ARRAY_SIZE(pmic_models) && pmic_models[model]) + seq_printf(seq, "%s %u.%u\n", pmic_models[model], + SOCINFO_MAJOR(die_rev), + SOCINFO_MINOR(die_rev)); + else + seq_printf(seq, "unknown (%d)\n", model); + } + + return 0; +} + static int qcom_show_pmic_die_revision(struct seq_file *seq, void *p) { struct socinfo *socinfo = seq->private; @@ -316,6 +365,7 @@ static int qcom_show_chip_id(struct seq_file *seq, void *p) QCOM_OPEN(build_id, qcom_show_build_id); QCOM_OPEN(pmic_model, qcom_show_pmic_model); +QCOM_OPEN(pmic_model_array, qcom_show_pmic_model_array); QCOM_OPEN(pmic_die_rev, qcom_show_pmic_die_revision); QCOM_OPEN(chip_id, qcom_show_chip_id); @@ -344,25 +394,27 @@ DEFINE_IMAGE_OPS(variant); DEFINE_IMAGE_OPS(oem); static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo, - struct socinfo *info) + struct socinfo *info, size_t info_size) { struct smem_image_version *versions; struct dentry *dentry; size_t size; int i; + unsigned int num_pmics; + unsigned int pmic_array_offset; qcom_socinfo->dbg_root = debugfs_create_dir("qcom_socinfo", NULL); qcom_socinfo->info.fmt = __le32_to_cpu(info->fmt); - debugfs_create_x32("info_fmt", 0400, qcom_socinfo->dbg_root, + debugfs_create_x32("info_fmt", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.fmt); switch (qcom_socinfo->info.fmt) { case SOCINFO_VERSION(0, 15): qcom_socinfo->info.nmodem_supported = __le32_to_cpu(info->nmodem_supported); - debugfs_create_u32("nmodem_supported", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("nmodem_supported", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.nmodem_supported); fallthrough; case SOCINFO_VERSION(0, 14): @@ -371,19 +423,19 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo, qcom_socinfo->info.num_defective_parts = __le32_to_cpu(info->num_defective_parts); qcom_socinfo->info.ndefective_parts_array_offset = __le32_to_cpu(info->ndefective_parts_array_offset); - debugfs_create_u32("num_clusters", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("num_clusters", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.num_clusters); - debugfs_create_u32("ncluster_array_offset", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("ncluster_array_offset", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.ncluster_array_offset); - debugfs_create_u32("num_defective_parts", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("num_defective_parts", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.num_defective_parts); - debugfs_create_u32("ndefective_parts_array_offset", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("ndefective_parts_array_offset", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.ndefective_parts_array_offset); fallthrough; case SOCINFO_VERSION(0, 13): qcom_socinfo->info.nproduct_id = __le32_to_cpu(info->nproduct_id); - debugfs_create_u32("nproduct_id", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("nproduct_id", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.nproduct_id); DEBUGFS_ADD(info, chip_id); fallthrough; @@ -395,21 +447,26 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo, qcom_socinfo->info.raw_device_num = __le32_to_cpu(info->raw_device_num); - debugfs_create_x32("chip_family", 0400, qcom_socinfo->dbg_root, + debugfs_create_x32("chip_family", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.chip_family); - debugfs_create_x32("raw_device_family", 0400, + debugfs_create_x32("raw_device_family", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.raw_device_family); - debugfs_create_x32("raw_device_number", 0400, + debugfs_create_x32("raw_device_number", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.raw_device_num); fallthrough; case SOCINFO_VERSION(0, 11): + num_pmics = le32_to_cpu(info->num_pmics); + pmic_array_offset = le32_to_cpu(info->pmic_array_offset); + if (pmic_array_offset + 2 * num_pmics * sizeof(u32) <= info_size) + DEBUGFS_ADD(info, pmic_model_array); + fallthrough; case SOCINFO_VERSION(0, 10): case SOCINFO_VERSION(0, 9): qcom_socinfo->info.foundry_id = __le32_to_cpu(info->foundry_id); - debugfs_create_u32("foundry_id", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("foundry_id", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.foundry_id); fallthrough; case SOCINFO_VERSION(0, 8): @@ -421,7 +478,7 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo, qcom_socinfo->info.hw_plat_subtype = __le32_to_cpu(info->hw_plat_subtype); - debugfs_create_u32("hardware_platform_subtype", 0400, + debugfs_create_u32("hardware_platform_subtype", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.hw_plat_subtype); fallthrough; @@ -429,28 +486,28 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo, qcom_socinfo->info.accessory_chip = __le32_to_cpu(info->accessory_chip); - debugfs_create_u32("accessory_chip", 0400, + debugfs_create_u32("accessory_chip", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.accessory_chip); fallthrough; case SOCINFO_VERSION(0, 4): qcom_socinfo->info.plat_ver = __le32_to_cpu(info->plat_ver); - debugfs_create_u32("platform_version", 0400, + debugfs_create_u32("platform_version", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.plat_ver); fallthrough; case SOCINFO_VERSION(0, 3): qcom_socinfo->info.hw_plat = __le32_to_cpu(info->hw_plat); - debugfs_create_u32("hardware_platform", 0400, + debugfs_create_u32("hardware_platform", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.hw_plat); fallthrough; case SOCINFO_VERSION(0, 2): qcom_socinfo->info.raw_ver = __le32_to_cpu(info->raw_ver); - debugfs_create_u32("raw_version", 0400, qcom_socinfo->dbg_root, + debugfs_create_u32("raw_version", 0444, qcom_socinfo->dbg_root, &qcom_socinfo->info.raw_ver); fallthrough; case SOCINFO_VERSION(0, 1): @@ -467,11 +524,11 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo, dentry = debugfs_create_dir(socinfo_image_names[i], qcom_socinfo->dbg_root); - debugfs_create_file("name", 0400, dentry, &versions[i], + debugfs_create_file("name", 0444, dentry, &versions[i], &qcom_image_name_ops); - debugfs_create_file("variant", 0400, dentry, &versions[i], + debugfs_create_file("variant", 0444, dentry, &versions[i], &qcom_image_variant_ops); - debugfs_create_file("oem", 0400, dentry, &versions[i], + debugfs_create_file("oem", 0444, dentry, &versions[i], &qcom_image_oem_ops); } } @@ -482,7 +539,7 @@ static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo) } #else static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo, - struct socinfo *info) + struct socinfo *info, size_t info_size) { } static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo) { } @@ -522,7 +579,7 @@ static int qcom_socinfo_probe(struct platform_device *pdev) if (IS_ERR(qs->soc_dev)) return PTR_ERR(qs->soc_dev); - socinfo_debugfs_init(qs, info); + socinfo_debugfs_init(qs, info, item_size); /* Feed the soc specific unique data into entropy pool */ add_device_randomness(info, item_size); diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 9b235fc90027..53387a72ca00 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/soc/renesas/rcar-sysc.h> #include "rcar-sysc.h" @@ -44,13 +45,13 @@ #define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ -#define SYSCSR_RETRIES 100 +#define SYSCSR_TIMEOUT 100 #define SYSCSR_DELAY_US 1 #define PWRER_RETRIES 100 #define PWRER_DELAY_US 1 -#define SYSCISR_RETRIES 1000 +#define SYSCISR_TIMEOUT 1000 #define SYSCISR_DELAY_US 1 #define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */ @@ -68,7 +69,8 @@ static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val; static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) { unsigned int sr_bit, reg_offs; - int k; + u32 val; + int ret; if (on) { sr_bit = SYSCSR_PONENB; @@ -79,13 +81,10 @@ static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) } /* Wait until SYSC is ready to accept a power request */ - for (k = 0; k < SYSCSR_RETRIES; k++) { - if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit)) - break; - udelay(SYSCSR_DELAY_US); - } - - if (k == SYSCSR_RETRIES) + ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCSR, val, + val & BIT(sr_bit), SYSCSR_DELAY_US, + SYSCSR_TIMEOUT); + if (ret) return -EAGAIN; /* Submit power shutoff or power resume request */ @@ -99,10 +98,9 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) { unsigned int isr_mask = BIT(sysc_ch->isr_bit); unsigned int chan_mask = BIT(sysc_ch->chan_bit); - unsigned int status; + unsigned int status, k; unsigned long flags; - int ret = 0; - int k; + int ret; spin_lock_irqsave(&rcar_sysc_lock, flags); @@ -145,13 +143,10 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) } /* Wait until the power shutoff or resume request has completed * */ - for (k = 0; k < SYSCISR_RETRIES; k++) { - if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask) - break; - udelay(SYSCISR_DELAY_US); - } - - if (k == SYSCISR_RETRIES) + ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCISR, status, + status & isr_mask, SYSCISR_DELAY_US, + SYSCISR_TIMEOUT); + if (ret) ret = -EIO; iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); @@ -439,6 +434,8 @@ static int __init rcar_sysc_pd_init(void) } error = of_genpd_add_provider_onecell(np, &domains->onecell_data); + if (!error) + of_node_set_flag(np, OF_POPULATED); out_put: of_node_put(np); diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index fc7f48a92288..5745d7e5908e 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -7,21 +7,19 @@ menuconfig SOC_SAMSUNG if SOC_SAMSUNG -config EXYNOS_ASV - bool "Exynos Adaptive Supply Voltage support" if COMPILE_TEST - depends on (ARCH_EXYNOS && EXYNOS_CHIPID) || COMPILE_TEST - select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS - # There is no need to enable these drivers for ARMv8 config EXYNOS_ASV_ARM bool "Exynos ASV ARMv7-specific driver extensions" if COMPILE_TEST - depends on EXYNOS_ASV + depends on EXYNOS_CHIPID config EXYNOS_CHIPID - bool "Exynos Chipid controller driver" if COMPILE_TEST + bool "Exynos ChipID controller and ASV driver" if COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST + select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS select MFD_SYSCON select SOC_BUS + help + Support for Samsung Exynos SoC ChipID and Adaptive Supply Voltage. config EXYNOS_PMU bool "Exynos PMU controller driver" if COMPILE_TEST diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index 59e8e9453f27..0c523a8de4eb 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -1,9 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_EXYNOS_ASV) += exynos-asv.o obj-$(CONFIG_EXYNOS_ASV_ARM) += exynos5422-asv.o -obj-$(CONFIG_EXYNOS_CHIPID) += exynos-chipid.o +obj-$(CONFIG_EXYNOS_CHIPID) += exynos-chipid.o exynos-asv.o obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \ diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c index 8abf4dfaa5c5..d60af8acc391 100644 --- a/drivers/soc/samsung/exynos-asv.c +++ b/drivers/soc/samsung/exynos-asv.c @@ -2,7 +2,9 @@ /* * Copyright (c) 2019 Samsung Electronics Co., Ltd. * http://www.samsung.com/ + * Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org> * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> + * Author: Krzysztof Kozlowski <krzk@kernel.org> * * Samsung Exynos SoC Adaptive Supply Voltage support */ @@ -10,12 +12,7 @@ #include <linux/cpu.h> #include <linux/device.h> #include <linux/errno.h> -#include <linux/init.h> -#include <linux/mfd/syscon.h> -#include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> #include <linux/pm_opp.h> #include <linux/regmap.h> #include <linux/soc/samsung/exynos-chipid.h> @@ -111,7 +108,7 @@ static int exynos_asv_update_opps(struct exynos_asv *asv) return 0; } -static int exynos_asv_probe(struct platform_device *pdev) +int exynos_asv_init(struct device *dev, struct regmap *regmap) { int (*probe_func)(struct exynos_asv *asv); struct exynos_asv *asv; @@ -119,39 +116,39 @@ static int exynos_asv_probe(struct platform_device *pdev) u32 product_id = 0; int ret, i; - cpu_dev = get_cpu_device(0); - ret = dev_pm_opp_get_opp_count(cpu_dev); - if (ret < 0) - return -EPROBE_DEFER; - - asv = devm_kzalloc(&pdev->dev, sizeof(*asv), GFP_KERNEL); + asv = devm_kzalloc(dev, sizeof(*asv), GFP_KERNEL); if (!asv) return -ENOMEM; - asv->chipid_regmap = device_node_to_regmap(pdev->dev.of_node); - if (IS_ERR(asv->chipid_regmap)) { - dev_err(&pdev->dev, "Could not find syscon regmap\n"); - return PTR_ERR(asv->chipid_regmap); + asv->chipid_regmap = regmap; + asv->dev = dev; + ret = regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, + &product_id); + if (ret < 0) { + dev_err(dev, "Cannot read revision from ChipID: %d\n", ret); + return -ENODEV; } - regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id); - switch (product_id & EXYNOS_MASK) { case 0xE5422000: probe_func = exynos5422_asv_init; break; default: - return -ENODEV; + dev_dbg(dev, "No ASV support for this SoC\n"); + devm_kfree(dev, asv); + return 0; } - ret = of_property_read_u32(pdev->dev.of_node, "samsung,asv-bin", + cpu_dev = get_cpu_device(0); + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret < 0) + return -EPROBE_DEFER; + + ret = of_property_read_u32(dev->of_node, "samsung,asv-bin", &asv->of_bin); if (ret < 0) asv->of_bin = -EINVAL; - asv->dev = &pdev->dev; - dev_set_drvdata(&pdev->dev, asv); - for (i = 0; i < ARRAY_SIZE(asv->subsys); i++) asv->subsys[i].asv = asv; @@ -161,17 +158,3 @@ static int exynos_asv_probe(struct platform_device *pdev) return exynos_asv_update_opps(asv); } - -static const struct of_device_id exynos_asv_of_device_ids[] = { - { .compatible = "samsung,exynos4210-chipid" }, - {} -}; - -static struct platform_driver exynos_asv_driver = { - .driver = { - .name = "exynos-asv", - .of_match_table = exynos_asv_of_device_ids, - }, - .probe = exynos_asv_probe, -}; -module_platform_driver(exynos_asv_driver); diff --git a/drivers/soc/samsung/exynos-asv.h b/drivers/soc/samsung/exynos-asv.h index 3fd1f2acd999..dcbe154db31e 100644 --- a/drivers/soc/samsung/exynos-asv.h +++ b/drivers/soc/samsung/exynos-asv.h @@ -68,4 +68,6 @@ static inline u32 exynos_asv_opp_get_frequency(const struct exynos_asv_subsys *s return __asv_get_table_entry(&subsys->table, level, 0); } +int exynos_asv_init(struct device *dev, struct regmap *regmap); + #endif /* __LINUX_SOC_EXYNOS_ASV_H */ diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index 1a76eade2ed6..5c1d0f97f766 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -2,20 +2,28 @@ /* * Copyright (c) 2019 Samsung Electronics Co., Ltd. * http://www.samsung.com/ + * Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org> * * Exynos - CHIP ID support * Author: Pankaj Dubey <pankaj.dubey@samsung.com> * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> + * Author: Krzysztof Kozlowski <krzk@kernel.org> + * + * Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support */ -#include <linux/io.h> +#include <linux/device.h> +#include <linux/errno.h> #include <linux/mfd/syscon.h> #include <linux/of.h> +#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/soc/samsung/exynos-chipid.h> #include <linux/sys_soc.h> +#include "exynos-asv.h" + static const struct exynos_soc_id { const char *name; unsigned int id; @@ -36,7 +44,7 @@ static const struct exynos_soc_id { { "EXYNOS7420", 0xE7420000 }, }; -static const char * __init product_id_to_soc_id(unsigned int product_id) +static const char *product_id_to_soc_id(unsigned int product_id) { int i; @@ -46,25 +54,17 @@ static const char * __init product_id_to_soc_id(unsigned int product_id) return NULL; } -static int __init exynos_chipid_early_init(void) +static int exynos_chipid_probe(struct platform_device *pdev) { struct soc_device_attribute *soc_dev_attr; struct soc_device *soc_dev; struct device_node *root; - struct device_node *syscon; struct regmap *regmap; u32 product_id; u32 revision; int ret; - syscon = of_find_compatible_node(NULL, NULL, - "samsung,exynos4210-chipid"); - if (!syscon) - return -ENODEV; - - regmap = device_node_to_regmap(syscon); - of_node_put(syscon); - + regmap = device_node_to_regmap(pdev->dev.of_node); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -74,7 +74,8 @@ static int __init exynos_chipid_early_init(void) revision = product_id & EXYNOS_REV_MASK; - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), + GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; @@ -84,20 +85,24 @@ static int __init exynos_chipid_early_init(void) of_property_read_string(root, "model", &soc_dev_attr->machine); of_node_put(root); - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision); + soc_dev_attr->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%x", revision); soc_dev_attr->soc_id = product_id_to_soc_id(product_id); if (!soc_dev_attr->soc_id) { pr_err("Unknown SoC\n"); - ret = -ENODEV; - goto err; + return -ENODEV; } /* please note that the actual registration will be deferred */ soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - ret = PTR_ERR(soc_dev); + if (IS_ERR(soc_dev)) + return PTR_ERR(soc_dev); + + ret = exynos_asv_init(&pdev->dev, regmap); + if (ret) goto err; - } + + platform_set_drvdata(pdev, soc_dev); dev_info(soc_device_to_device(soc_dev), "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n", @@ -106,9 +111,31 @@ static int __init exynos_chipid_early_init(void) return 0; err: - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); + soc_device_unregister(soc_dev); + return ret; } -arch_initcall(exynos_chipid_early_init); +static int exynos_chipid_remove(struct platform_device *pdev) +{ + struct soc_device *soc_dev = platform_get_drvdata(pdev); + + soc_device_unregister(soc_dev); + + return 0; +} + +static const struct of_device_id exynos_chipid_of_device_ids[] = { + { .compatible = "samsung,exynos4210-chipid" }, + {} +}; + +static struct platform_driver exynos_chipid_driver = { + .driver = { + .name = "exynos-chipid", + .of_match_table = exynos_chipid_of_device_ids, + }, + .probe = exynos_chipid_probe, + .remove = exynos_chipid_remove, +}; +builtin_platform_driver(exynos_chipid_driver); diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index ab8582971bfc..5ec0c13f0aaf 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -16,7 +16,7 @@ #include <linux/delay.h> #include <linux/of_address.h> #include <linux/of_platform.h> -#include <linux/sched.h> +#include <linux/pm_runtime.h> struct exynos_pm_domain_config { /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */ @@ -73,15 +73,15 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) return exynos_pd_power(domain, false); } -static const struct exynos_pm_domain_config exynos4210_cfg __initconst = { +static const struct exynos_pm_domain_config exynos4210_cfg = { .local_pwr_cfg = 0x7, }; -static const struct exynos_pm_domain_config exynos5433_cfg __initconst = { +static const struct exynos_pm_domain_config exynos5433_cfg = { .local_pwr_cfg = 0xf, }; -static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { +static const struct of_device_id exynos_pm_domain_of_match[] = { { .compatible = "samsung,exynos4210-pd", .data = &exynos4210_cfg, @@ -92,7 +92,7 @@ static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { { }, }; -static __init const char *exynos_get_domain_name(struct device_node *node) +static const char *exynos_get_domain_name(struct device_node *node) { const char *name; @@ -101,60 +101,44 @@ static __init const char *exynos_get_domain_name(struct device_node *node) return kstrdup_const(name, GFP_KERNEL); } -static __init int exynos4_pm_init_power_domain(void) +static int exynos_pd_probe(struct platform_device *pdev) { - struct device_node *np; - const struct of_device_id *match; - - for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) { - const struct exynos_pm_domain_config *pm_domain_cfg; - struct exynos_pm_domain *pd; - int on; + const struct exynos_pm_domain_config *pm_domain_cfg; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct of_phandle_args child, parent; + struct exynos_pm_domain *pd; + int on, ret; - pm_domain_cfg = match->data; + pm_domain_cfg = of_device_get_match_data(dev); + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - of_node_put(np); - return -ENOMEM; - } - pd->pd.name = exynos_get_domain_name(np); - if (!pd->pd.name) { - kfree(pd); - of_node_put(np); - return -ENOMEM; - } + pd->pd.name = exynos_get_domain_name(np); + if (!pd->pd.name) + return -ENOMEM; - pd->base = of_iomap(np, 0); - if (!pd->base) { - pr_warn("%s: failed to map memory\n", __func__); - kfree_const(pd->pd.name); - kfree(pd); - continue; - } - - pd->pd.power_off = exynos_pd_power_off; - pd->pd.power_on = exynos_pd_power_on; - pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; + pd->base = of_iomap(np, 0); + if (!pd->base) { + kfree_const(pd->pd.name); + return -ENODEV; + } - on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; + pd->pd.power_off = exynos_pd_power_off; + pd->pd.power_on = exynos_pd_power_on; + pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; - pm_genpd_init(&pd->pd, NULL, !on); - of_genpd_add_provider_simple(np, &pd->pd); - } + on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; - /* Assign the child power domains to their parents */ - for_each_matching_node(np, exynos_pm_domain_of_match) { - struct of_phandle_args child, parent; + pm_genpd_init(&pd->pd, NULL, !on); + ret = of_genpd_add_provider_simple(np, &pd->pd); + if (ret == 0 && of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", 0, &parent) == 0) { child.np = np; child.args_count = 0; - if (of_parse_phandle_with_args(np, "power-domains", - "#power-domain-cells", 0, - &parent) != 0) - continue; - if (of_genpd_add_subdomain(&parent, &child)) pr_warn("%pOF failed to add subdomain: %pOF\n", parent.np, child.np); @@ -163,6 +147,21 @@ static __init int exynos4_pm_init_power_domain(void) parent.np, child.np); } - return 0; + pm_runtime_enable(dev); + return ret; +} + +static struct platform_driver exynos_pd_driver = { + .probe = exynos_pd_probe, + .driver = { + .name = "exynos-pd", + .of_match_table = exynos_pm_domain_of_match, + .suppress_bind_attrs = true, + } +}; + +static __init int exynos4_pm_init_power_domain(void) +{ + return platform_driver_register(&exynos_pd_driver); } core_initcall(exynos4_pm_init_power_domain); diff --git a/drivers/soc/sunxi/sunxi_mbus.c b/drivers/soc/sunxi/sunxi_mbus.c index e9925c8487d7..d90e4a264b6f 100644 --- a/drivers/soc/sunxi/sunxi_mbus.c +++ b/drivers/soc/sunxi/sunxi_mbus.c @@ -23,12 +23,7 @@ static const char * const sunxi_mbus_devices[] = { "allwinner,sun7i-a20-display-engine", "allwinner,sun8i-a23-display-engine", "allwinner,sun8i-a33-display-engine", - "allwinner,sun8i-a83t-display-engine", - "allwinner,sun8i-h3-display-engine", - "allwinner,sun8i-r40-display-engine", - "allwinner,sun8i-v3s-display-engine", "allwinner,sun9i-a80-display-engine", - "allwinner,sun50i-a64-display-engine", /* * And now we have the regular devices connected to the MBUS diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index d4c7bd59429e..42833e33a96c 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -283,7 +283,7 @@ int sunxi_sram_release(struct device *dev) EXPORT_SYMBOL(sunxi_sram_release); struct sunxi_sramc_variant { - bool has_emac_clock; + int num_emac_clocks; }; static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = { @@ -291,20 +291,31 @@ static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = { }; static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = { - .has_emac_clock = true, + .num_emac_clocks = 1, }; static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = { - .has_emac_clock = true, + .num_emac_clocks = 1, +}; + +static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = { + .num_emac_clocks = 2, }; #define SUNXI_SRAM_EMAC_CLOCK_REG 0x30 static bool sunxi_sram_regmap_accessible_reg(struct device *dev, unsigned int reg) { - if (reg == SUNXI_SRAM_EMAC_CLOCK_REG) - return true; - return false; + const struct sunxi_sramc_variant *variant; + + variant = of_device_get_match_data(dev); + + if (reg < SUNXI_SRAM_EMAC_CLOCK_REG) + return false; + if (reg > SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4) + return false; + + return true; } static struct regmap_config sunxi_sram_emac_clock_regmap = { @@ -312,7 +323,7 @@ static struct regmap_config sunxi_sram_emac_clock_regmap = { .val_bits = 32, .reg_stride = 4, /* last defined register */ - .max_register = SUNXI_SRAM_EMAC_CLOCK_REG, + .max_register = SUNXI_SRAM_EMAC_CLOCK_REG + 4, /* other devices have no business accessing other registers */ .readable_reg = sunxi_sram_regmap_accessible_reg, .writeable_reg = sunxi_sram_regmap_accessible_reg, @@ -343,7 +354,7 @@ static int sunxi_sram_probe(struct platform_device *pdev) if (!d) return -ENOMEM; - if (variant->has_emac_clock) { + if (variant->num_emac_clocks > 0) { emac_clock = devm_regmap_init_mmio(&pdev->dev, base, &sunxi_sram_emac_clock_regmap); @@ -387,6 +398,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = { .compatible = "allwinner,sun50i-h5-system-control", .data = &sun50i_a64_sramc_variant, }, + { + .compatible = "allwinner,sun50i-h616-system-control", + .data = &sun50i_h616_sramc_variant, + }, { }, }; MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match); diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index b495b0d5d0fa..312ba0f98ad7 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -9,6 +9,7 @@ #include <linux/io.h> #include <linux/init.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/sys_soc.h> #include <linux/dma/ti-cppi5.h> @@ -1517,15 +1518,13 @@ EXPORT_SYMBOL_GPL(k3_ringacc_dmarings_init); static int k3_ringacc_probe(struct platform_device *pdev) { const struct ringacc_match_data *match_data; - const struct of_device_id *match; struct device *dev = &pdev->dev; struct k3_ringacc *ringacc; int ret; - match = of_match_node(k3_ringacc_of_match, dev->of_node); - if (!match) + match_data = of_device_get_match_data(&pdev->dev); + if (!match_data) return -ENODEV; - match_data = match->data; ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL); if (!ringacc) diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index 7b5cb5d48f7d..591d14ebcb11 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -758,6 +758,7 @@ static int knav_dma_probe(struct platform_device *pdev) for_each_child_of_node(node, child) { ret = dma_init(node, child); if (ret) { + of_node_put(child); dev_err(&pdev->dev, "init failed with %d\n", ret); break; } diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 2e521f1eda96..2ac3856b8d42 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1087,6 +1087,7 @@ static int knav_queue_setup_regions(struct knav_device *kdev, for_each_child_of_node(regions, child) { region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); if (!region) { + of_node_put(child); dev_err(dev, "out of memory allocating region\n"); return -ENOMEM; } @@ -1399,6 +1400,7 @@ static int knav_queue_init_qmgrs(struct knav_device *kdev, for_each_child_of_node(qmgrs, child) { qmgr = devm_kzalloc(dev, sizeof(*qmgr), GFP_KERNEL); if (!qmgr) { + of_node_put(child); dev_err(dev, "out of memory allocating qmgr\n"); return -ENOMEM; } @@ -1498,6 +1500,7 @@ static int knav_queue_init_pdsps(struct knav_device *kdev, for_each_child_of_node(pdsps, child) { pdsp = devm_kzalloc(dev, sizeof(*pdsp), GFP_KERNEL); if (!pdsp) { + of_node_put(child); dev_err(dev, "out of memory allocating pdsp\n"); return -ENOMEM; } diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c index 77f0051358f1..bf1468e5bccb 100644 --- a/drivers/soc/ti/omap_prm.c +++ b/drivers/soc/ti/omap_prm.c @@ -860,6 +860,7 @@ static int omap_prm_reset_init(struct platform_device *pdev, const struct omap_rst_map *map; struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev); char buf[32]; + u32 v; /* * Check if we have controllable resets. If either rstctrl is non-zero @@ -907,6 +908,16 @@ static int omap_prm_reset_init(struct platform_device *pdev, map++; } + /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */ + if (prm->data->rstmap == rst_map_012) { + v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); + if ((v & reset->mask) != reset->mask) { + dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v); + writel_relaxed(reset->mask, reset->prm->base + + reset->prm->data->rstctrl); + } + } + return devm_reset_controller_register(&pdev->dev, &reset->rcdev); } diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 64f3e3105540..7bab4bbaf02d 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -535,7 +535,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) ret = am33xx_push_sram_idle(); if (ret) - goto err_free_sram; + goto err_unsetup_rtc; am33xx_pm_set_ipc_ops(); @@ -575,6 +575,9 @@ err_pm_runtime_put: err_pm_runtime_disable: pm_runtime_disable(dev); wkup_m3_ipc_put(m3_ipc); +err_unsetup_rtc: + iounmap(rtc_base_virt); + clk_put(rtc_fck); err_free_sram: am33xx_pm_free_sram(); pm33xx_dev = NULL; diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index 5d6e7132a5c4..f22ac1edbdd0 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -161,6 +161,53 @@ static struct regmap_config regmap_conf = { .reg_stride = 4, }; +static int pruss_cfg_of_init(struct device *dev, struct pruss *pruss) +{ + struct device_node *np = dev_of_node(dev); + struct device_node *child; + struct resource res; + int ret; + + child = of_get_child_by_name(np, "cfg"); + if (!child) { + dev_err(dev, "%pOF is missing its 'cfg' node\n", child); + return -ENODEV; + } + + if (of_address_to_resource(child, 0, &res)) { + ret = -ENOMEM; + goto node_put; + } + + pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!pruss->cfg_base) { + ret = -ENOMEM; + goto node_put; + } + + regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child, + (u64)res.start); + regmap_conf.max_register = resource_size(&res) - 4; + + pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base, + ®map_conf); + kfree(regmap_conf.name); + if (IS_ERR(pruss->cfg_regmap)) { + dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n", + PTR_ERR(pruss->cfg_regmap)); + ret = PTR_ERR(pruss->cfg_regmap); + goto node_put; + } + + ret = pruss_clk_init(pruss, child); + if (ret) + dev_err(dev, "pruss_clk_init failed, ret = %d\n", ret); + +node_put: + of_node_put(child); + return ret; +} + static int pruss_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -239,56 +286,18 @@ static int pruss_probe(struct platform_device *pdev) goto rpm_disable; } - child = of_get_child_by_name(np, "cfg"); - if (!child) { - dev_err(dev, "%pOF is missing its 'cfg' node\n", child); - ret = -ENODEV; + ret = pruss_cfg_of_init(dev, pruss); + if (ret < 0) goto rpm_put; - } - - if (of_address_to_resource(child, 0, &res)) { - ret = -ENOMEM; - goto node_put; - } - - pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res)); - if (!pruss->cfg_base) { - ret = -ENOMEM; - goto node_put; - } - - regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child, - (u64)res.start); - regmap_conf.max_register = resource_size(&res) - 4; - - pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base, - ®map_conf); - kfree(regmap_conf.name); - if (IS_ERR(pruss->cfg_regmap)) { - dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n", - PTR_ERR(pruss->cfg_regmap)); - ret = PTR_ERR(pruss->cfg_regmap); - goto node_put; - } - - ret = pruss_clk_init(pruss, child); - if (ret) { - dev_err(dev, "failed to setup coreclk-mux\n"); - goto node_put; - } ret = devm_of_platform_populate(dev); if (ret) { dev_err(dev, "failed to register child devices\n"); - goto node_put; + goto rpm_put; } - of_node_put(child); - return 0; -node_put: - of_node_put(child); rpm_put: pm_runtime_put_sync(dev); rpm_disable: diff --git a/drivers/soc/zte/Kconfig b/drivers/soc/zte/Kconfig deleted file mode 100644 index 1cf1938da541..000000000000 --- a/drivers/soc/zte/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# ZTE SoC drivers -# -menuconfig SOC_ZTE - depends on ARCH_ZX || COMPILE_TEST - bool "ZTE SoC driver support" - -if SOC_ZTE - -config ZX2967_PM_DOMAINS - bool "ZX2967 PM domains" - depends on PM_GENERIC_DOMAINS - -endif diff --git a/drivers/soc/zte/Makefile b/drivers/soc/zte/Makefile deleted file mode 100644 index 728c677addcd..000000000000 --- a/drivers/soc/zte/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# ZTE SOC drivers -# -obj-$(CONFIG_ZX2967_PM_DOMAINS) += zx2967_pm_domains.o -obj-$(CONFIG_ZX2967_PM_DOMAINS) += zx296718_pm_domains.o diff --git a/drivers/soc/zte/zx296718_pm_domains.c b/drivers/soc/zte/zx296718_pm_domains.c deleted file mode 100644 index 4daab06bbc26..000000000000 --- a/drivers/soc/zte/zx296718_pm_domains.c +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2017 ZTE Ltd. - * - * Author: Baoyou Xie <baoyou.xie@linaro.org> - */ - -#include <dt-bindings/soc/zte,pm_domains.h> -#include "zx2967_pm_domains.h" - -static u16 zx296718_offsets[REG_ARRAY_SIZE] = { - [REG_CLKEN] = 0x18, - [REG_ISOEN] = 0x1c, - [REG_RSTEN] = 0x20, - [REG_PWREN] = 0x24, - [REG_ACK_SYNC] = 0x28, -}; - -enum { - PCU_DM_VOU = 0, - PCU_DM_SAPPU, - PCU_DM_VDE, - PCU_DM_VCE, - PCU_DM_HDE, - PCU_DM_VIU, - PCU_DM_USB20, - PCU_DM_USB21, - PCU_DM_USB30, - PCU_DM_HSIC, - PCU_DM_GMAC, - PCU_DM_TS, -}; - -static struct zx2967_pm_domain vou_domain = { - .dm = { - .name = "vou_domain", - }, - .bit = PCU_DM_VOU, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain sappu_domain = { - .dm = { - .name = "sappu_domain", - }, - .bit = PCU_DM_SAPPU, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain vde_domain = { - .dm = { - .name = "vde_domain", - }, - .bit = PCU_DM_VDE, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain vce_domain = { - .dm = { - .name = "vce_domain", - }, - .bit = PCU_DM_VCE, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain hde_domain = { - .dm = { - .name = "hde_domain", - }, - .bit = PCU_DM_HDE, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain viu_domain = { - .dm = { - .name = "viu_domain", - }, - .bit = PCU_DM_VIU, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain usb20_domain = { - .dm = { - .name = "usb20_domain", - }, - .bit = PCU_DM_USB20, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain usb21_domain = { - .dm = { - .name = "usb21_domain", - }, - .bit = PCU_DM_USB21, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain usb30_domain = { - .dm = { - .name = "usb30_domain", - }, - .bit = PCU_DM_USB30, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain hsic_domain = { - .dm = { - .name = "hsic_domain", - }, - .bit = PCU_DM_HSIC, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain gmac_domain = { - .dm = { - .name = "gmac_domain", - }, - .bit = PCU_DM_GMAC, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct zx2967_pm_domain ts_domain = { - .dm = { - .name = "ts_domain", - }, - .bit = PCU_DM_TS, - .polarity = PWREN, - .reg_offset = zx296718_offsets, -}; - -static struct generic_pm_domain *zx296718_pm_domains[] = { - [DM_ZX296718_VOU] = &vou_domain.dm, - [DM_ZX296718_SAPPU] = &sappu_domain.dm, - [DM_ZX296718_VDE] = &vde_domain.dm, - [DM_ZX296718_VCE] = &vce_domain.dm, - [DM_ZX296718_HDE] = &hde_domain.dm, - [DM_ZX296718_VIU] = &viu_domain.dm, - [DM_ZX296718_USB20] = &usb20_domain.dm, - [DM_ZX296718_USB21] = &usb21_domain.dm, - [DM_ZX296718_USB30] = &usb30_domain.dm, - [DM_ZX296718_HSIC] = &hsic_domain.dm, - [DM_ZX296718_GMAC] = &gmac_domain.dm, - [DM_ZX296718_TS] = &ts_domain.dm, -}; - -static int zx296718_pd_probe(struct platform_device *pdev) -{ - return zx2967_pd_probe(pdev, - zx296718_pm_domains, - ARRAY_SIZE(zx296718_pm_domains)); -} - -static const struct of_device_id zx296718_pm_domain_matches[] = { - { .compatible = "zte,zx296718-pcu", }, - { }, -}; - -static struct platform_driver zx296718_pd_driver = { - .driver = { - .name = "zx296718-powerdomain", - .of_match_table = zx296718_pm_domain_matches, - }, - .probe = zx296718_pd_probe, -}; - -static int __init zx296718_pd_init(void) -{ - return platform_driver_register(&zx296718_pd_driver); -} -subsys_initcall(zx296718_pd_init); diff --git a/drivers/soc/zte/zx2967_pm_domains.c b/drivers/soc/zte/zx2967_pm_domains.c deleted file mode 100644 index a4503e31b616..000000000000 --- a/drivers/soc/zte/zx2967_pm_domains.c +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2017 ZTE Ltd. - * - * Author: Baoyou Xie <baoyou.xie@linaro.org> - */ - -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/of.h> - -#include "zx2967_pm_domains.h" - -#define PCU_DM_CLKEN(zpd) ((zpd)->reg_offset[REG_CLKEN]) -#define PCU_DM_ISOEN(zpd) ((zpd)->reg_offset[REG_ISOEN]) -#define PCU_DM_RSTEN(zpd) ((zpd)->reg_offset[REG_RSTEN]) -#define PCU_DM_PWREN(zpd) ((zpd)->reg_offset[REG_PWREN]) -#define PCU_DM_ACK_SYNC(zpd) ((zpd)->reg_offset[REG_ACK_SYNC]) - -static void __iomem *pcubase; - -static int zx2967_power_on(struct generic_pm_domain *domain) -{ - struct zx2967_pm_domain *zpd = (struct zx2967_pm_domain *)domain; - unsigned long loop = 1000; - u32 val; - - val = readl_relaxed(pcubase + PCU_DM_PWREN(zpd)); - if (zpd->polarity == PWREN) - val |= BIT(zpd->bit); - else - val &= ~BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_PWREN(zpd)); - - do { - udelay(1); - val = readl_relaxed(pcubase + PCU_DM_ACK_SYNC(zpd)) - & BIT(zpd->bit); - } while (--loop && !val); - - if (!loop) { - pr_err("Error: %s %s fail\n", __func__, domain->name); - return -EIO; - } - - val = readl_relaxed(pcubase + PCU_DM_RSTEN(zpd)); - val |= BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_RSTEN(zpd)); - udelay(5); - - val = readl_relaxed(pcubase + PCU_DM_ISOEN(zpd)); - val &= ~BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_ISOEN(zpd)); - udelay(5); - - val = readl_relaxed(pcubase + PCU_DM_CLKEN(zpd)); - val |= BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_CLKEN(zpd)); - udelay(5); - - pr_debug("poweron %s\n", domain->name); - - return 0; -} - -static int zx2967_power_off(struct generic_pm_domain *domain) -{ - struct zx2967_pm_domain *zpd = (struct zx2967_pm_domain *)domain; - unsigned long loop = 1000; - u32 val; - - val = readl_relaxed(pcubase + PCU_DM_CLKEN(zpd)); - val &= ~BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_CLKEN(zpd)); - udelay(5); - - val = readl_relaxed(pcubase + PCU_DM_ISOEN(zpd)); - val |= BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_ISOEN(zpd)); - udelay(5); - - val = readl_relaxed(pcubase + PCU_DM_RSTEN(zpd)); - val &= ~BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_RSTEN(zpd)); - udelay(5); - - val = readl_relaxed(pcubase + PCU_DM_PWREN(zpd)); - if (zpd->polarity == PWREN) - val &= ~BIT(zpd->bit); - else - val |= BIT(zpd->bit); - writel_relaxed(val, pcubase + PCU_DM_PWREN(zpd)); - - do { - udelay(1); - val = readl_relaxed(pcubase + PCU_DM_ACK_SYNC(zpd)) - & BIT(zpd->bit); - } while (--loop && val); - - if (!loop) { - pr_err("Error: %s %s fail\n", __func__, domain->name); - return -EIO; - } - - pr_debug("poweroff %s\n", domain->name); - - return 0; -} - -int zx2967_pd_probe(struct platform_device *pdev, - struct generic_pm_domain **zx_pm_domains, - int domain_num) -{ - struct genpd_onecell_data *genpd_data; - struct resource *res; - int i; - - genpd_data = devm_kzalloc(&pdev->dev, sizeof(*genpd_data), GFP_KERNEL); - if (!genpd_data) - return -ENOMEM; - - genpd_data->domains = zx_pm_domains; - genpd_data->num_domains = domain_num; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pcubase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pcubase)) - return PTR_ERR(pcubase); - - for (i = 0; i < domain_num; ++i) { - zx_pm_domains[i]->power_on = zx2967_power_on; - zx_pm_domains[i]->power_off = zx2967_power_off; - - pm_genpd_init(zx_pm_domains[i], NULL, false); - } - - of_genpd_add_provider_onecell(pdev->dev.of_node, genpd_data); - dev_info(&pdev->dev, "powerdomain init ok\n"); - return 0; -} diff --git a/drivers/soc/zte/zx2967_pm_domains.h b/drivers/soc/zte/zx2967_pm_domains.h deleted file mode 100644 index f586c02410ff..000000000000 --- a/drivers/soc/zte/zx2967_pm_domains.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Header for ZTE's Power Domain Driver support - * - * Copyright (C) 2017 ZTE Ltd. - * - * Author: Baoyou Xie <baoyou.xie@linaro.org> - */ - -#ifndef __ZTE_ZX2967_PM_DOMAIN_H -#define __ZTE_ZX2967_PM_DOMAIN_H - -#include <linux/platform_device.h> -#include <linux/pm_domain.h> - -enum { - REG_CLKEN, - REG_ISOEN, - REG_RSTEN, - REG_PWREN, - REG_PWRDN, - REG_ACK_SYNC, - - /* The size of the array - must be last */ - REG_ARRAY_SIZE, -}; - -enum zx2967_power_polarity { - PWREN, - PWRDN, -}; - -struct zx2967_pm_domain { - struct generic_pm_domain dm; - const u16 bit; - const enum zx2967_power_polarity polarity; - const u16 *reg_offset; -}; - -int zx2967_pd_probe(struct platform_device *pdev, - struct generic_pm_domain **zx_pm_domains, - int domain_num); - -#endif /* __ZTE_ZX2967_PM_DOMAIN_H */ |