From 5b0a5e8f93e04129a2115dd5883ad5ca561c009a Mon Sep 17 00:00:00 2001 From: Lionel VITTE Date: Thu, 11 Jul 2019 14:12:05 +0200 Subject: [PATCH 22/30] ARM stm32mp1 r2 SOC --- drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/st/Kconfig | 17 +++ drivers/soc/st/Makefile | 2 + drivers/soc/st/stm32_hdp.c | 242 ++++++++++++++++++++++++++++++++++++ drivers/soc/st/stm32_pm_domain.c | 212 +++++++++++++++++++++++++++++++ include/dt-bindings/soc/stm32-hdp.h | 108 ++++++++++++++++ 7 files changed, 583 insertions(+) create mode 100644 drivers/soc/st/Kconfig create mode 100644 drivers/soc/st/Makefile create mode 100644 drivers/soc/st/stm32_hdp.c create mode 100644 drivers/soc/st/stm32_pm_domain.c create mode 100644 include/dt-bindings/soc/stm32-hdp.h diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index c07b4a8..f2bd1ce 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -11,6 +11,7 @@ source "drivers/soc/qcom/Kconfig" source "drivers/soc/renesas/Kconfig" source "drivers/soc/rockchip/Kconfig" source "drivers/soc/samsung/Kconfig" +source "drivers/soc/st/Kconfig" source "drivers/soc/sunxi/Kconfig" source "drivers/soc/tegra/Kconfig" source "drivers/soc/ti/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 113e884..a16f673 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -18,6 +18,7 @@ obj-y += qcom/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ +obj-$(CONFIG_ARCH_STM32) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_SOC_TI) += ti/ diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig new file mode 100644 index 0000000..8ab6049 --- /dev/null +++ b/drivers/soc/st/Kconfig @@ -0,0 +1,17 @@ +if ARCH_STM32 + +config STM32_PM_DOMAINS + bool "STM32 PM domains" + depends on MACH_STM32MP157 + select PM_GENERIC_DOMAINS + default y if MACH_STM32MP157 + +config STM32_HDP + bool "STMicroelectronics STM32MP157 Hardware Debug Port (HDP) pin control" + depends on MACH_STM32MP157 + default n if MACH_STM32MP157 + help + The Hardware Debug Port allows the observation of internal signals. By using multiplexers, + up to 16 signals for each of 8-bit output can be observed. + +endif # ARCH_STM32 diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile new file mode 100644 index 0000000..85905b7 --- /dev/null +++ b/drivers/soc/st/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o +obj-$(CONFIG_STM32_HDP) += stm32_hdp.o diff --git a/drivers/soc/st/stm32_hdp.c b/drivers/soc/st/stm32_hdp.c new file mode 100644 index 0000000..6408ac6 --- /dev/null +++ b/drivers/soc/st/stm32_hdp.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Christophe Roullier + * for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HDP_CTRL_ENABLE 1 +#define HDP_CTRL_DISABLE 0 + +enum { + HDP_CTRL = 0, + HDP_MUX = 0x4, + HDP_VAL = 0x10, + HDP_GPOSET = 0x14, + HDP_GPOCLR = 0x18, + HDP_GPOVAL = 0x1c, + HDP_VERR = 0x3f4, + HDP_IPIDR = 0x3f8, + HDP_SIDR = 0x3fc +} HDP_register_offsets; + +struct data_priv { + struct clk *clk; + int clk_is_enabled; + struct dentry *pwr_dentry; + unsigned char __iomem *hdp_membase; + unsigned int hdp_ctrl; + unsigned int hdp_mux; +}; + +/* enable/disable */ +static int stm32_hdp_enable_set(void *data, int val) +{ + struct data_priv *e = (struct data_priv *)data; + + if (!e->clk) + return -EPERM; + + if (val == 1) { + if (clk_prepare_enable(e->clk) < 0) { + pr_err("Failed to enable HDP clock\n"); + return -EPERM; + } + e->clk_is_enabled = 1; + } else { + clk_disable_unprepare(e->clk); + e->clk_is_enabled = 0; + } + return 0; +} + +static int stm32_hdp_fops_set(void *data, u64 val) +{ + unsigned char __iomem *addr = (unsigned char __iomem *)data; + + writel_relaxed(val, addr); + + return 0; +} + +static int stm32_hdp_fops_get(void *data, u64 *val) +{ + unsigned char __iomem *addr = (unsigned char __iomem *)data; + + *val = readl_relaxed(addr); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(stm32_hdp_fops, stm32_hdp_fops_get, + stm32_hdp_fops_set, "0x%llx\n"); + +int stm32_hdp_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct resource *res; + + struct data_priv *data; + struct dentry *r; + + int ret; + const __be32 *getmuxing; + u32 muxing, version; + + if (!np) + return -ENODEV; + + data = devm_kzalloc(&pdev->dev, sizeof(struct data_priv), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->hdp_membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->hdp_membase)) + return PTR_ERR(data->hdp_membase); + + /* Get HDP clocks */ + data->clk = devm_clk_get(dev, "hdp"); + if (IS_ERR(data->clk)) { + dev_err(dev, "No HDP CK clock provided...\n"); + return PTR_ERR(data->clk); + } + + /* Enable clock */ + ret = stm32_hdp_enable_set(data, 1); + if (ret != 0) + return ret; + + getmuxing = of_get_property(np, "muxing-hdp", NULL); + if (!getmuxing) { + dev_err(dev, + "no muxing-hdp property in node\n"); + /* Disable clock */ + ret = stm32_hdp_enable_set(data, 0); + if (ret != 0) + return ret; + + return -EINVAL; + } + + /* add hdp directory */ + r = debugfs_create_dir("hdp", NULL); + if (!r) { + dev_err(dev, "Unable to create HDP debugFS\n"); + /* Disable clock */ + ret = stm32_hdp_enable_set(data, 0); + if (ret != 0) + return ret; + + return -ENODEV; + } + + debugfs_create_file("ctrl", 0644, r, + data->hdp_membase + HDP_CTRL, &stm32_hdp_fops); + debugfs_create_file("mux", 0644, r, + data->hdp_membase + HDP_MUX, &stm32_hdp_fops); + debugfs_create_file("val", 0644, r, + data->hdp_membase + HDP_VAL, &stm32_hdp_fops); + debugfs_create_file("gposet", 0644, r, + data->hdp_membase + HDP_GPOSET, &stm32_hdp_fops); + debugfs_create_file("gpoclr", 0644, r, + data->hdp_membase + HDP_GPOCLR, &stm32_hdp_fops); + debugfs_create_file("gpoval", 0644, r, + data->hdp_membase + HDP_GPOVAL, &stm32_hdp_fops); + + /* Enable HDP */ + writel(HDP_CTRL_ENABLE, data->hdp_membase + HDP_CTRL); + + /* HDP Multiplexing */ + muxing = of_read_number(getmuxing, + of_n_addr_cells(np)); + + writel(muxing, data->hdp_membase + HDP_MUX); + + platform_set_drvdata(pdev, data); + + /* Get Majeur, Minor version */ + version = readl(data->hdp_membase + HDP_VERR); + + dev_info(dev, "STM32 HDP version %d.%d initialized\n", + version >> 4, version & 0x0F); + + return 0; +} + +static int stm32_hdp_remove(struct platform_device *pdev) +{ + struct data_priv *data = platform_get_drvdata(pdev); + + /* Disable HDP */ + writel(HDP_CTRL_DISABLE, data->hdp_membase + HDP_CTRL); + + if (data->clk) { + if (data->clk_is_enabled) + clk_disable_unprepare(data->clk); + } + + pr_info("driver STM32 HDP removed\n"); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int stm32_hdp_suspend(struct device *dev) +{ + struct data_priv *data = dev_get_drvdata(dev); + + data->hdp_ctrl = readl_relaxed(data->hdp_membase + HDP_CTRL); + data->hdp_mux = readl_relaxed(data->hdp_membase + HDP_MUX); + + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static int stm32_hdp_resume(struct device *dev) +{ + struct data_priv *data = dev_get_drvdata(dev); + + writel_relaxed(data->hdp_ctrl, data->hdp_membase + HDP_CTRL); + writel_relaxed(data->hdp_mux, data->hdp_membase + HDP_MUX); + + pinctrl_pm_select_default_state(dev); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(stm32_hdp_pm_ops, + stm32_hdp_suspend, + stm32_hdp_resume); + +static const struct of_device_id hdp_match[] = { + { .compatible = "st,stm32mp1-hdp",}, + { } +}; +MODULE_DEVICE_TABLE(of, hdp_match); + +static struct platform_driver hdp_driver = { + .probe = stm32_hdp_probe, + .remove = stm32_hdp_remove, + .driver = { + .name = "hdp", + .of_match_table = hdp_match, + .pm = &stm32_hdp_pm_ops, + }, +}; + +module_platform_driver(hdp_driver); diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c new file mode 100644 index 0000000..0386624 --- /dev/null +++ b/drivers/soc/st/stm32_pm_domain.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + * Author: Olivier Bideau for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SMC(domain, state) \ +{ \ + struct arm_smccc_res res; \ + arm_smccc_smc(0x82001008, domain, state, 0, \ + 0, 0, 0, 0, &res); \ +} + +#define STM32_SMC_PD_DOMAIN_ON 0 +#define STM32_SMC_PD_DOMAIN_OFF 1 + +struct stm32_pm_domain { + struct device *dev; + struct generic_pm_domain genpd; + int id; +}; + +static int stm32_pd_power_off(struct generic_pm_domain *domain) +{ + struct stm32_pm_domain *priv = container_of(domain, + struct stm32_pm_domain, + genpd); + + SMC(priv->id, STM32_SMC_PD_DOMAIN_OFF); + + dev_dbg(priv->dev, "%s OFF\n", domain->name); + + return 0; +} + +static int stm32_pd_power_on(struct generic_pm_domain *domain) +{ + struct stm32_pm_domain *priv = container_of(domain, + struct stm32_pm_domain, + genpd); + + SMC(priv->id, STM32_SMC_PD_DOMAIN_ON); + + dev_dbg(priv->dev, "%s ON\n", domain->name); + + return 0; +} + +static void stm32_pm_domain_remove(struct stm32_pm_domain *domain) +{ + int ret; + + ret = pm_genpd_remove(&domain->genpd); + if (ret) + dev_err(domain->dev, "failed to remove PM domain %s: %d\n", + domain->genpd.name, ret); +} + +static int stm32_pm_domain_add(struct stm32_pm_domain *domain, + struct device *dev, + struct device_node *np) +{ + int ret; + + domain->dev = dev; + domain->genpd.name = np->name; + domain->genpd.power_off = stm32_pd_power_off; + domain->genpd.power_on = stm32_pd_power_on; + domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; + + ret = of_property_read_u32(np, "reg", &domain->id); + if (ret) { + dev_err(domain->dev, "no domain ID\n"); + return ret; + } + + ret = pm_genpd_init(&domain->genpd, NULL, 0); + if (ret < 0) { + dev_err(domain->dev, "failed to initialise PM domain %s: %d\n", + np->name, ret); + return ret; + } + + ret = of_genpd_add_provider_simple(np, &domain->genpd); + if (ret < 0) { + dev_err(domain->dev, "failed to register PM domain %s: %d\n", + np->name, ret); + stm32_pm_domain_remove(domain); + return ret; + } + + dev_info(domain->dev, "domain %s registered\n", np->name); + + return 0; +} + +static void stm32_pm_subdomain_add(struct stm32_pm_domain *domain, + struct device *dev, + struct device_node *np) +{ + struct device_node *np_child; + int ret; + + for_each_child_of_node(np, np_child) { + struct stm32_pm_domain *sub_domain; + + sub_domain = devm_kzalloc(dev, sizeof(*sub_domain), GFP_KERNEL); + if (!sub_domain) + continue; + + sub_domain->dev = dev; + sub_domain->genpd.name = np_child->name; + sub_domain->genpd.power_off = stm32_pd_power_off; + sub_domain->genpd.power_on = stm32_pd_power_on; + sub_domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; + + ret = of_property_read_u32(np_child, "reg", &sub_domain->id); + if (ret) { + dev_err(sub_domain->dev, "no domain ID\n"); + devm_kfree(dev, sub_domain); + continue; + } + + ret = pm_genpd_init(&sub_domain->genpd, NULL, 0); + if (ret < 0) { + dev_err(sub_domain->dev, "failed to initialise PM domain %s: %d\n" + , np_child->name, ret); + devm_kfree(dev, sub_domain); + continue; + } + + ret = of_genpd_add_provider_simple(np_child, + &sub_domain->genpd); + if (ret < 0) { + dev_err(sub_domain->dev, "failed to register PM domain %s: %d\n" + , np_child->name, ret); + stm32_pm_domain_remove(sub_domain); + devm_kfree(dev, sub_domain); + continue; + } + + ret = pm_genpd_add_subdomain(&domain->genpd, + &sub_domain->genpd); + + if (ret < 0) { + dev_err(sub_domain->dev, "failed to add Sub PM domain %s: %d\n" + , np_child->name, ret); + stm32_pm_domain_remove(sub_domain); + devm_kfree(dev, sub_domain); + continue; + } + + dev_info(sub_domain->dev, "subdomain %s registered\n", + np_child->name); + } +} + +static int stm32_pm_domain_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node, *child_np; + int ret; + + for_each_child_of_node(np, child_np) { + struct stm32_pm_domain *domain; + + domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); + if (!domain) + continue; + + ret = stm32_pm_domain_add(domain, dev, child_np); + if (ret) { + devm_kfree(dev, domain); + continue; + } + + stm32_pm_subdomain_add(domain, dev, child_np); + } + + dev_info(dev, "domains probed\n"); + + return 0; +} + +static const struct of_device_id stm32_pm_domain_matches[] = { + { .compatible = "st,stm32mp157c-pd", }, + { }, +}; + +static struct platform_driver stm32_pm_domains_driver = { + .probe = stm32_pm_domain_probe, + .driver = { + .name = "stm32-pm-domain", + .of_match_table = stm32_pm_domain_matches, + }, +}; + +static int __init stm32_pm_domains_init(void) +{ + return platform_driver_register(&stm32_pm_domains_driver); +} +core_initcall(stm32_pm_domains_init); diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h new file mode 100644 index 0000000..d986653 --- /dev/null +++ b/include/dt-bindings/soc/stm32-hdp.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Roullier Christophe + * for STMicroelectronics. + */ + +#ifndef _DT_BINDINGS_STM32_HDP_H +#define _DT_BINDINGS_STM32_HDP_H + +#define STM32_HDP(port, value) ((value) << ((port) * 4)) + +/* define HDP Pins number*/ +#define HDP0_PWR_PWRWAKE_SYS 0 +#define HDP0_CM4_SLEEPDEEP 1 +#define HDP0_PWR_STDBY_WKUP 2 +#define HDP0_PWR_ENCOMP_VDDCORE 3 +#define HDP0_BSEC_OUT_SEC_NIDEN 4 +#define HDP0_RCC_CM4_SLEEPDEEP 6 +#define HDP0_GPU_DBG7 7 +#define HDP0_DDRCTRL_LP_REQ 8 +#define HDP0_PWR_DDR_RET_ENABLE_N 9 +#define HDP0_GPOVAL_0 15 + +#define HDP1_PWR_PWRWAKE_MCU 0 +#define HDP1_CM4_HALTED 1 +#define HDP1_CA7_NAXIERRIRQ 2 +#define HDP1_PWR_OKIN_MR 3 +#define HDP1_BSEC_OUT_SEC_DBGEN 4 +#define HDP1_EXTI_SYS_WAKEUP 5 +#define HDP1_RCC_PWRDS_MPU 6 +#define HDP1_GPU_DBG6 7 +#define HDP1_DDRCTRL_DFI_CTRLUPD_REQ 8 +#define HDP1_DDRCTRL_CACTIVE_DDRC_ASR 9 +#define HDP1_GPOVAL_1 15 + +#define HDP2_PWR_PWRWAKE_MPU 0 +#define HDP2_CM4_RXEV 1 +#define HDP2_CA7_NPMUIRQ1 2 +#define HDP2_CA7_NFIQOUT1 3 +#define HDP2_BSEC_IN_RSTCORE_N 4 +#define HDP2_EXTI_C2_WAKEUP 5 +#define HDP2_RCC_PWRDS_MCU 6 +#define HDP2_GPU_DBG5 7 +#define HDP2_DDRCTRL_DFI_INIT_COMPLETE 8 +#define HDP2_DDRCTRL_PERF_OP_IS_REFRESH 9 +#define HDP2_DDRCTRL_GSKP_DFI_LP_REQ 10 +#define HDP2_GPOVAL_2 15 + +#define HDP3_PWR_SEL_VTH_VDD_CORE 0 +#define HDP3_CM4_TXEV 1 +#define HDP3_CA7_NPMUIRQ0 2 +#define HDP3_CA7_NFIQOUT0 3 +#define HDP3_BSEC_OUT_SEC_DFTLOCK 4 +#define HDP3_EXTI_C1_WAKEUP 5 +#define HDP3_RCC_PWRDS_SYS 6 +#define HDP3_GPU_DBG4 7 +#define HDP3_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE0 8 +#define HDP3_DDRCTRL_CACTIVE_1 9 +#define HDP3_GPOVAL_3 15 + +#define HDP4_PWR_PDDS 0 +#define HDP4_CM4_SLEEPING 1 +#define HDP4_CA7_NRESET1 2 +#define HDP4_CA7_NIRQOUT1 3 +#define HDP4_BSEC_OUT_SEC_DFTEN 4 +#define HDP4_BSEC_OUT_SEC_DBGSWENABLE 5 +#define HDP4_ETH_OUT_PMT_INTR_O 6 +#define HDP4_GPU_DBG3 7 +#define HDP4_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE1 8 +#define HDP4_DDRCTRL_CACTIVE_0 9 +#define HDP4_GPOVAL_4 15 + +#define HDP5_CA7_STANDBYWFIL2 0 +#define HDP5_PWR_VTH_VDDCORE_ACK 1 +#define HDP5_CA7_NRESET0 2 +#define HDP5_CA7_NIRQOUT0 3 +#define HDP5_BSEC_IN_PWROK 4 +#define HDP5_BSEC_OUT_SEC_DEVICEEN 5 +#define HDP5_ETH_OUT_LPI_INTR_O 6 +#define HDP5_GPU_DBG2 7 +#define HDP5_DDRCTRL_CACTIVE_DDRC 8 +#define HDP5_DDRCTRL_WR_CREDIT_CNT 9 +#define HDP5_GPOVAL_5 15 + +#define HDP6_CA7_STANDBYWFI1 0 +#define HDP6_CA7_STANDBYWFE1 1 +#define HDP6_CA7_EVENT0 2 +#define HDP6_CA7_DBGACK1 3 +#define HDP6_BSEC_OUT_SEC_SPNIDEN 5 +#define HDP6_ETH_OUT_MAC_SPEED_O1 6 +#define HDP6_GPU_DBG1 7 +#define HDP6_DDRCTRL_CSYSACK_DDRC 8 +#define HDP6_DDRCTRL_LPR_CREDIT_CNT 9 +#define HDP6_GPOVAL_6 15 + +#define HDP7_CA7_STANDBYWFI0 0 +#define HDP7_CA7_STANDBYWFE0 1 +#define HDP7_CA7_DBGACK0 3 +#define HDP7_BSEC_OUT_FUSE_OK 4 +#define HDP7_BSEC_OUT_SEC_SPIDEN 5 +#define HDP7_ETH_OUT_MAC_SPEED_O0 6 +#define HDP7_GPU_DBG0 7 +#define HDP7_DDRCTRL_CSYSREQ_DDRC 8 +#define HDP7_DDRCTRL_HPR_CREDIT_CNT 9 +#define HDP7_GPOVAL_7 15 + +#endif /* _DT_BINDINGS_STM32_HDP_H */ -- 2.7.4