From d52fad262041217be0a0e7049253186ec9cfb2a6 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 18 Jun 2015 17:11:32 -0700 Subject: soc: add stubs for brcmstb SoC's Used on BCM7xxx Set-Top Box chips (e.g., BCM7445). Signed-off-by: Brian Norris Signed-off-by: Florian Fainelli --- drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/brcmstb/Kconfig | 9 +++++++++ drivers/soc/brcmstb/Makefile | 1 + drivers/soc/brcmstb/common.c | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 45 insertions(+) create mode 100644 drivers/soc/brcmstb/Kconfig create mode 100644 drivers/soc/brcmstb/Makefile create mode 100644 drivers/soc/brcmstb/common.c (limited to 'drivers/soc') diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 96ddecb..c9c0fcc 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -1,5 +1,6 @@ menu "SOC (System On Chip) specific Drivers" +source "drivers/soc/brcmstb/Kconfig" source "drivers/soc/mediatek/Kconfig" source "drivers/soc/qcom/Kconfig" source "drivers/soc/sunxi/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 0b12d77..4e27f10 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -2,6 +2,7 @@ # Makefile for the Linux Kernel SOC specific device drivers. # +obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/ obj-$(CONFIG_MACH_DOVE) += dove/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_QCOM) += qcom/ diff --git a/drivers/soc/brcmstb/Kconfig b/drivers/soc/brcmstb/Kconfig new file mode 100644 index 0000000..39cab3b --- /dev/null +++ b/drivers/soc/brcmstb/Kconfig @@ -0,0 +1,9 @@ +menuconfig SOC_BRCMSTB + bool "Broadcom STB SoC drivers" + depends on ARM + help + Enables drivers for the Broadcom Set-Top Box (STB) series of chips. + This option alone enables only some support code, while the drivers + can be enabled individually within this menu. + + If unsure, say N. diff --git a/drivers/soc/brcmstb/Makefile b/drivers/soc/brcmstb/Makefile new file mode 100644 index 0000000..183280e --- /dev/null +++ b/drivers/soc/brcmstb/Makefile @@ -0,0 +1 @@ +obj-y += common.o diff --git a/drivers/soc/brcmstb/common.c b/drivers/soc/brcmstb/common.c new file mode 100644 index 0000000..c262c02 --- /dev/null +++ b/drivers/soc/brcmstb/common.c @@ -0,0 +1,33 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * Copyright © 2015 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include + +static const struct of_device_id brcmstb_machine_match[] = { + { .compatible = "brcm,brcmstb", }, + { } +}; + +bool soc_is_brcmstb(void) +{ + struct device_node *root; + + root = of_find_node_by_path("/"); + if (!root) + return false; + + return of_match_node(brcmstb_machine_match, root) != NULL; +} -- cgit v1.1 From bbe379fc7ca5cae09b1bc44fe5ee4173ad883fbf Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Fri, 11 Sep 2015 21:05:20 +0800 Subject: soc: mediatek: Move the initial setting of pmic wrap interrupt before requesting irq. The watchdog may not be initialized by the bootloader, even if the rest of the pwrap is. Move the watchdog initialization out of pwrap_init() to make sure the watchdog is always initialized and not only when the pwrap is uninitialized. Signed-off-by: Henry Chen Acked-by: Sascha Hauer Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 8bc7b41..105597a 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -725,10 +725,6 @@ static int pwrap_init(struct pmic_wrapper *wrp) pwrap_writel(wrp, 0x1, PWRAP_WACS2_EN); pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD); pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN); - pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT); - pwrap_writel(wrp, 0xffffffff, PWRAP_WDT_SRC_EN); - pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); - pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN); if (pwrap_is_mt8135(wrp)) { /* enable pwrap events and pwrap bridge in AP side */ @@ -896,6 +892,12 @@ static int pwrap_probe(struct platform_device *pdev) return -ENODEV; } + /* Initialize watchdog, may not be done by the bootloader */ + pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT); + pwrap_writel(wrp, 0xffffffff, PWRAP_WDT_SRC_EN); + pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); + pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN); + irq = platform_get_irq(pdev, 0); ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH, "mt-pmic-pwrap", wrp); -- cgit v1.1 From 47e90154fafd1a1310e3c5baed77d8f4c33ab271 Mon Sep 17 00:00:00 2001 From: Eddie Huang Date: Wed, 26 Aug 2015 15:14:41 +0800 Subject: soc: mediatek: add scpsys support active_wakeup Register gpd_dev_ops.active_wakeup function to support keep power during suspend state. And add flag to each power domain to decide whether keep power during suspend or not. Signed-off-by: Chunfeng Yun Signed-off-by: Eddie Huang Acked-by: Sascha Hauer Reviewed-by: Daniel Kurtz Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-scpsys.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 164a7d8..55ab08f 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -68,6 +68,7 @@ struct scp_domain_data { u32 sram_pdn_ack_bits; u32 bus_prot_mask; enum clk_id clk_id; + bool active_wakeup; }; static const struct scp_domain_data scp_domain_data[] __initconst = { @@ -128,6 +129,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = MT8173_CLK_NONE, + .active_wakeup = true, }, [MT8173_POWER_DOMAIN_MFG_ASYNC] = { .name = "mfg_async", @@ -172,6 +174,7 @@ struct scp_domain { u32 sram_pdn_bits; u32 sram_pdn_ack_bits; u32 bus_prot_mask; + bool active_wakeup; }; struct scp { @@ -371,6 +374,17 @@ out: return ret; } +static bool scpsys_active_wakeup(struct device *dev) +{ + struct generic_pm_domain *genpd; + struct scp_domain *scpd; + + genpd = pd_to_genpd(dev->pm_domain); + scpd = container_of(genpd, struct scp_domain, genpd); + + return scpd->active_wakeup; +} + static int __init scpsys_probe(struct platform_device *pdev) { struct genpd_onecell_data *pd_data; @@ -428,12 +442,14 @@ static int __init scpsys_probe(struct platform_device *pdev) scpd->sram_pdn_bits = data->sram_pdn_bits; scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits; scpd->bus_prot_mask = data->bus_prot_mask; + scpd->active_wakeup = data->active_wakeup; if (data->clk_id != MT8173_CLK_NONE) scpd->clk = clk[data->clk_id]; genpd->name = data->name; genpd->power_off = scpsys_power_off; genpd->power_on = scpsys_power_on; + genpd->dev_ops.active_wakeup = scpsys_active_wakeup; /* * Initially turn on all domains to make the domains usable -- cgit v1.1 From 9a764234eee689ea800424ab99b08ff07a8bdbcd Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 14 Sep 2015 12:09:34 -0700 Subject: soc: brcmstb: Add Bus Interface Unit control setup Broadcom STB SoCs (brcmstb) require an early setup of their Bus Interface Unit control register, this needs to happen before SMP is brought up because it affects how the CPU complex will be interfaced to the memory controller. Add support code which properly initializes the BIU registers based on whether "brcm,write-pairing" is present in Device Tree, and take care of saving and restoring credit register settings during system-wide suspend/resume operations. Acked-by: Gregory Fong Signed-off-by: Florian Fainelli --- drivers/soc/brcmstb/Makefile | 2 +- drivers/soc/brcmstb/biuctrl.c | 116 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/brcmstb/biuctrl.c (limited to 'drivers/soc') diff --git a/drivers/soc/brcmstb/Makefile b/drivers/soc/brcmstb/Makefile index 183280e..9120b27 100644 --- a/drivers/soc/brcmstb/Makefile +++ b/drivers/soc/brcmstb/Makefile @@ -1 +1 @@ -obj-y += common.o +obj-y += common.o biuctrl.o diff --git a/drivers/soc/brcmstb/biuctrl.c b/drivers/soc/brcmstb/biuctrl.c new file mode 100644 index 0000000..9049c076f --- /dev/null +++ b/drivers/soc/brcmstb/biuctrl.c @@ -0,0 +1,116 @@ +/* + * Broadcom STB SoCs Bus Unit Interface controls + * + * Copyright (C) 2015, Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "brcmstb: " KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#define CPU_CREDIT_REG_OFFSET 0x184 +#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000 + +static void __iomem *cpubiuctrl_base; +static bool mcp_wr_pairing_en; + +static int __init mcp_write_pairing_set(void) +{ + u32 creds = 0; + + if (!cpubiuctrl_base) + return -1; + + creds = readl_relaxed(cpubiuctrl_base + CPU_CREDIT_REG_OFFSET); + if (mcp_wr_pairing_en) { + pr_info("MCP: Enabling write pairing\n"); + writel_relaxed(creds | CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK, + cpubiuctrl_base + CPU_CREDIT_REG_OFFSET); + } else if (creds & CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK) { + pr_info("MCP: Disabling write pairing\n"); + writel_relaxed(creds & ~CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK, + cpubiuctrl_base + CPU_CREDIT_REG_OFFSET); + } else { + pr_info("MCP: Write pairing already disabled\n"); + } + + return 0; +} + +static int __init setup_hifcpubiuctrl_regs(void) +{ + struct device_node *np; + int ret = 0; + + np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl"); + if (!np) { + pr_err("missing BIU control node\n"); + return -ENODEV; + } + + cpubiuctrl_base = of_iomap(np, 0); + if (!cpubiuctrl_base) { + pr_err("failed to remap BIU control base\n"); + ret = -ENOMEM; + goto out; + } + + mcp_wr_pairing_en = of_property_read_bool(np, "brcm,write-pairing"); +out: + of_node_put(np); + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static u32 cpu_credit_reg_dump; /* for save/restore */ + +static int brcmstb_cpu_credit_reg_suspend(void) +{ + if (cpubiuctrl_base) + cpu_credit_reg_dump = + readl_relaxed(cpubiuctrl_base + CPU_CREDIT_REG_OFFSET); + return 0; +} + +static void brcmstb_cpu_credit_reg_resume(void) +{ + if (cpubiuctrl_base) + writel_relaxed(cpu_credit_reg_dump, + cpubiuctrl_base + CPU_CREDIT_REG_OFFSET); +} + +static struct syscore_ops brcmstb_cpu_credit_syscore_ops = { + .suspend = brcmstb_cpu_credit_reg_suspend, + .resume = brcmstb_cpu_credit_reg_resume, +}; +#endif + + +void __init brcmstb_biuctrl_init(void) +{ + int ret; + + setup_hifcpubiuctrl_regs(); + + ret = mcp_write_pairing_set(); + if (ret) { + pr_err("MCP: Unable to disable write pairing!\n"); + return; + } + +#ifdef CONFIG_PM_SLEEP + register_syscore_ops(&brcmstb_cpu_credit_syscore_ops); +#endif +} -- cgit v1.1 From 96ee19becc3bd7b2cebae5828c3eacfebb50b993 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 13 Oct 2015 13:49:04 -0700 Subject: soc: ti: add firmware file name as part of the driver Currently firmware file name is included in the DTS. This is not scalable as user has to change the DTS if they need upgrade to a new firmware. Instead, add the firmware file name in the driver itself. As long as there is no API change, new firmware upgrade is easy and require no driver change. User is expected to copy the firmware image to the file system and add a sym link to the new firmware for doing an upgrade. Driver add a array of firmware file names to search for the available firmware blobs. This scheme also prepare the driver for future changes to API if ever happens. In such case it is assumed that driver needs to change to accommodate the new firmware and new firmware file name will get added to the array. Also update the DT document to remove the firmware attribute and add description about firmware in the driver documentation. Signed-off-by: Murali Karicheri Acked-by: Arnd Bergmann Signed-off-by: Santosh Shilimkar --- drivers/soc/ti/knav_qmss.h | 1 - drivers/soc/ti/knav_qmss_queue.c | 47 ++++++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 20 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h index 51da234..c31b8d8 100644 --- a/drivers/soc/ti/knav_qmss.h +++ b/drivers/soc/ti/knav_qmss.h @@ -135,7 +135,6 @@ struct knav_pdsp_info { }; void __iomem *intd; u32 __iomem *iram; - const char *firmware; u32 id; struct list_head list; }; diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 6d8646d..06d9de8 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -68,6 +68,12 @@ static DEFINE_MUTEX(knav_dev_lock); idx < (kdev)->num_queues_in_use; \ idx++, inst = knav_queue_idx_to_inst(kdev, idx)) +/* All firmware file names end up here. List the firmware file names below. + * Newest followed by older ones. Search is done from start of the array + * until a firmware file is found. + */ +const char *knav_acc_firmwares[] = {"ks2_qmss_pdsp_acc48.bin"}; + /** * knav_queue_notify: qmss queue notfier call * @@ -1439,7 +1445,6 @@ static int knav_queue_init_pdsps(struct knav_device *kdev, struct device *dev = kdev->dev; struct knav_pdsp_info *pdsp; struct device_node *child; - int ret; for_each_child_of_node(pdsps, child) { pdsp = devm_kzalloc(dev, sizeof(*pdsp), GFP_KERNEL); @@ -1448,17 +1453,6 @@ static int knav_queue_init_pdsps(struct knav_device *kdev, return -ENOMEM; } pdsp->name = knav_queue_find_name(child); - ret = of_property_read_string(child, "firmware", - &pdsp->firmware); - if (ret < 0 || !pdsp->firmware) { - dev_err(dev, "unknown firmware for pdsp %s\n", - pdsp->name); - devm_kfree(dev, pdsp); - continue; - } - dev_dbg(dev, "pdsp name %s fw name :%s\n", pdsp->name, - pdsp->firmware); - pdsp->iram = knav_queue_map_reg(kdev, child, KNAV_QUEUE_PDSP_IRAM_REG_INDEX); @@ -1489,9 +1483,9 @@ static int knav_queue_init_pdsps(struct knav_device *kdev, } of_property_read_u32(child, "id", &pdsp->id); list_add_tail(&pdsp->list, &kdev->pdsps); - dev_dbg(dev, "added pdsp %s: command %p, iram %p, regs %p, intd %p, firmware %s\n", + dev_dbg(dev, "added pdsp %s: command %p, iram %p, regs %p, intd %p\n", pdsp->name, pdsp->command, pdsp->iram, pdsp->regs, - pdsp->intd, pdsp->firmware); + pdsp->intd); } return 0; } @@ -1518,14 +1512,29 @@ static int knav_queue_load_pdsp(struct knav_device *kdev, { int i, ret, fwlen; const struct firmware *fw; + bool found = false; u32 *fwdata; - ret = request_firmware(&fw, pdsp->firmware, kdev->dev); - if (ret) { - dev_err(kdev->dev, "failed to get firmware %s for pdsp %s\n", - pdsp->firmware, pdsp->name); - return ret; + for (i = 0; i < ARRAY_SIZE(knav_acc_firmwares); i++) { + if (knav_acc_firmwares[i]) { + ret = request_firmware(&fw, + knav_acc_firmwares[i], + kdev->dev); + if (!ret) { + found = true; + break; + } + } + } + + if (!found) { + dev_err(kdev->dev, "failed to get firmware for pdsp\n"); + return -ENODEV; } + + dev_info(kdev->dev, "firmware file %s downloaded for PDSP\n", + knav_acc_firmwares[i]); + writel_relaxed(pdsp->id + 1, pdsp->command + 0x18); /* download the firmware */ fwdata = (u32 *)fw->data; -- cgit v1.1 From 045016902bf7abeeb2a86fc9284c30dce228f055 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 13 Oct 2015 13:49:04 -0700 Subject: soc: ti: qmss: make acc queue support optional in the driver acc channels are available only if accumulator PDSP is loaded and running in the SoC. As this requires firmware and user may not have firmware in the file system, make the accumulator queue support available in qmss driver optional. To use accumulator queus user needs to add firmware to the file system and boot up kernel. Signed-off-by: Murali Karicheri Signed-off-by: Santosh Shilimkar --- drivers/soc/ti/knav_qmss.h | 2 ++ drivers/soc/ti/knav_qmss_acc.c | 10 ++++++++-- drivers/soc/ti/knav_qmss_queue.c | 20 +++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h index c31b8d8..6ff936c 100644 --- a/drivers/soc/ti/knav_qmss.h +++ b/drivers/soc/ti/knav_qmss.h @@ -137,6 +137,8 @@ struct knav_pdsp_info { u32 __iomem *iram; u32 id; struct list_head list; + bool loaded; + bool started; }; struct knav_qmgr_info { diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c index ef6f69d..37c4aa9 100644 --- a/drivers/soc/ti/knav_qmss_acc.c +++ b/drivers/soc/ti/knav_qmss_acc.c @@ -482,8 +482,8 @@ struct knav_range_ops knav_acc_range_ops = { * Return 0 on success or error */ int knav_init_acc_range(struct knav_device *kdev, - struct device_node *node, - struct knav_range_info *range) + struct device_node *node, + struct knav_range_info *range) { struct knav_acc_channel *acc; struct knav_pdsp_info *pdsp; @@ -526,6 +526,12 @@ int knav_init_acc_range(struct knav_device *kdev, return -EINVAL; } + if (!pdsp->started) { + dev_err(kdev->dev, "pdsp id %d not started for range %s\n", + info->pdsp_id, range->name); + return -ENODEV; + } + info->pdsp = pdsp; channels = range->num_queues; if (of_get_property(node, "multi-queue", NULL)) { diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 06d9de8..f3a0b6a 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1504,6 +1504,8 @@ static int knav_queue_stop_pdsp(struct knav_device *kdev, dev_err(kdev->dev, "timed out on pdsp %s stop\n", pdsp->name); return ret; } + pdsp->loaded = false; + pdsp->started = false; return 0; } @@ -1592,16 +1594,24 @@ static int knav_queue_start_pdsps(struct knav_device *kdev) int ret; knav_queue_stop_pdsps(kdev); - /* now load them all */ + /* now load them all. We return success even if pdsp + * is not loaded as acc channels are optional on having + * firmware availability in the system. We set the loaded + * and stated flag and when initialize the acc range, check + * it and init the range only if pdsp is started. + */ for_each_pdsp(kdev, pdsp) { ret = knav_queue_load_pdsp(kdev, pdsp); - if (ret < 0) - return ret; + if (!ret) + pdsp->loaded = true; } for_each_pdsp(kdev, pdsp) { - ret = knav_queue_start_pdsp(kdev, pdsp); - WARN_ON(ret); + if (pdsp->loaded) { + ret = knav_queue_start_pdsp(kdev, pdsp); + if (!ret) + pdsp->started = true; + } } return 0; } -- cgit v1.1 From 41b3e0f067c26dd17837aa49fba13fcb5c6319e1 Mon Sep 17 00:00:00 2001 From: James Liao Date: Wed, 7 Oct 2015 17:14:40 +0800 Subject: soc: mediatek: Fix random hang up issue while kernel init In kernel late init, it turns off all unused clocks, which needs to access subsystem registers such as VENC and VENC_LT. Accessing MT8173 VENC registers needs two top clocks, mm_sel and venc_sel. Accessing VENC_LT registers needs mm_sel and venclt_sel. So we need to keep these clocks on before accessing their registers. This patch keeps venc_sel / venclt_sel clock on when VENC / VENC_LT's power is on, to prevent system hang up while accessing its registeres. Signed-off-by: James Liao Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-scpsys.c | 67 +++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 55ab08f..4d4203c 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -54,12 +54,16 @@ #define PWR_STATUS_USB BIT(25) enum clk_id { + MT8173_CLK_NONE, MT8173_CLK_MM, MT8173_CLK_MFG, - MT8173_CLK_NONE, - MT8173_CLK_MAX = MT8173_CLK_NONE, + MT8173_CLK_VENC, + MT8173_CLK_VENC_LT, + MT8173_CLK_MAX, }; +#define MAX_CLKS 2 + struct scp_domain_data { const char *name; u32 sta_mask; @@ -67,7 +71,7 @@ struct scp_domain_data { u32 sram_pdn_bits; u32 sram_pdn_ack_bits; u32 bus_prot_mask; - enum clk_id clk_id; + enum clk_id clk_id[MAX_CLKS]; bool active_wakeup; }; @@ -78,7 +82,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_VDE_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(12, 12), - .clk_id = MT8173_CLK_MM, + .clk_id = {MT8173_CLK_MM}, }, [MT8173_POWER_DOMAIN_VENC] = { .name = "venc", @@ -86,7 +90,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_VEN_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = MT8173_CLK_MM, + .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, }, [MT8173_POWER_DOMAIN_ISP] = { .name = "isp", @@ -94,7 +98,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_ISP_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(13, 12), - .clk_id = MT8173_CLK_MM, + .clk_id = {MT8173_CLK_MM}, }, [MT8173_POWER_DOMAIN_MM] = { .name = "mm", @@ -102,7 +106,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_DIS_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(12, 12), - .clk_id = MT8173_CLK_MM, + .clk_id = {MT8173_CLK_MM}, .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | MT8173_TOP_AXI_PROT_EN_MM_M1, }, @@ -112,7 +116,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_VEN2_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = MT8173_CLK_MM, + .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, }, [MT8173_POWER_DOMAIN_AUDIO] = { .name = "audio", @@ -120,7 +124,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_AUDIO_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = MT8173_CLK_NONE, + .clk_id = {MT8173_CLK_NONE}, }, [MT8173_POWER_DOMAIN_USB] = { .name = "usb", @@ -128,7 +132,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_USB_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = MT8173_CLK_NONE, + .clk_id = {MT8173_CLK_NONE}, .active_wakeup = true, }, [MT8173_POWER_DOMAIN_MFG_ASYNC] = { @@ -137,7 +141,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_MFG_ASYNC_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = 0, - .clk_id = MT8173_CLK_MFG, + .clk_id = {MT8173_CLK_MFG}, }, [MT8173_POWER_DOMAIN_MFG_2D] = { .name = "mfg_2d", @@ -145,7 +149,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_MFG_2D_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(13, 12), - .clk_id = MT8173_CLK_NONE, + .clk_id = {MT8173_CLK_NONE}, }, [MT8173_POWER_DOMAIN_MFG] = { .name = "mfg", @@ -153,7 +157,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { .ctl_offs = SPM_MFG_PWR_CON, .sram_pdn_bits = GENMASK(13, 8), .sram_pdn_ack_bits = GENMASK(21, 16), - .clk_id = MT8173_CLK_NONE, + .clk_id = {MT8173_CLK_NONE}, .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | MT8173_TOP_AXI_PROT_EN_MFG_M0 | MT8173_TOP_AXI_PROT_EN_MFG_M1 | @@ -168,7 +172,7 @@ struct scp; struct scp_domain { struct generic_pm_domain genpd; struct scp *scp; - struct clk *clk; + struct clk *clk[MAX_CLKS]; u32 sta_mask; void __iomem *ctl_addr; u32 sram_pdn_bits; @@ -215,11 +219,16 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) u32 sram_pdn_ack = scpd->sram_pdn_ack_bits; u32 val; int ret; + int i; + + for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) { + ret = clk_prepare_enable(scpd->clk[i]); + if (ret) { + for (--i; i >= 0; i--) + clk_disable_unprepare(scpd->clk[i]); - if (scpd->clk) { - ret = clk_prepare_enable(scpd->clk); - if (ret) goto err_clk; + } } val = readl(ctl_addr); @@ -285,7 +294,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) return 0; err_pwr_ack: - clk_disable_unprepare(scpd->clk); + for (i = MAX_CLKS - 1; i >= 0; i--) { + if (scpd->clk[i]) + clk_disable_unprepare(scpd->clk[i]); + } err_clk: dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); @@ -302,6 +314,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) u32 pdn_ack = scpd->sram_pdn_ack_bits; u32 val; int ret; + int i; if (scpd->bus_prot_mask) { ret = mtk_infracfg_set_bus_protection(scp->infracfg, @@ -363,8 +376,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) expired = true; } - if (scpd->clk) - clk_disable_unprepare(scpd->clk); + for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) + clk_disable_unprepare(scpd->clk[i]); return 0; @@ -389,7 +402,7 @@ static int __init scpsys_probe(struct platform_device *pdev) { struct genpd_onecell_data *pd_data; struct resource *res; - int i, ret; + int i, j, ret; struct scp *scp; struct clk *clk[MT8173_CLK_MAX]; @@ -419,6 +432,14 @@ static int __init scpsys_probe(struct platform_device *pdev) if (IS_ERR(clk[MT8173_CLK_MFG])) return PTR_ERR(clk[MT8173_CLK_MFG]); + clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); + if (IS_ERR(clk[MT8173_CLK_VENC])) + return PTR_ERR(clk[MT8173_CLK_VENC]); + + clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); + if (IS_ERR(clk[MT8173_CLK_VENC_LT])) + return PTR_ERR(clk[MT8173_CLK_VENC_LT]); + scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "infracfg"); if (IS_ERR(scp->infracfg)) { @@ -443,8 +464,8 @@ static int __init scpsys_probe(struct platform_device *pdev) scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits; scpd->bus_prot_mask = data->bus_prot_mask; scpd->active_wakeup = data->active_wakeup; - if (data->clk_id != MT8173_CLK_NONE) - scpd->clk = clk[data->clk_id]; + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) + scpd->clk[j] = clk[data->clk_id[j]]; genpd->name = data->name; genpd->power_off = scpsys_power_off; -- cgit v1.1