ARM: SoC platform updates for v4.4

New and/or improved SoC support for this release:
 
  - Marvell Berlin:
    * Enable standard DT-based cpufreq
    * Add CPU hotplug support
  - Freescale:
    * Ethernet init for i.MX7D
    * Suspend/resume support for i.MX6UL
  - Allwinner:
    * Support for R8 chipset (used on NTC's $9 C.H.I.P board)
  - Mediatek:
    * SMP support for some platforms
  - Uniphier:
    * L2 support
    * Cleaned up SMP support, etc.
 
 + A handful of other patches around above functionality, and a few other
 smaller changes.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWQCmaAAoJEIwa5zzehBx3F/0QAKIYmvmJM3sUanNEEwhRilx+
 3xhSgld7e25suLGwrNapTkd8VzVB4b8GnJhNShNk+l5WqfqICHCB4Aru2NmJHY8V
 yPj5vBrgJTVMnIiH7CRDPz9IlwAkWM4MmWi4PgFuhrk1T/0wPKPNMc40OWOloTeD
 gA5YmbbX1hNOqKoI/z+DK7CEdp1lHrEjeYIbnQ0SldFzkY9NKhrI784gtcz3si6E
 19pFQ9LA7EtEv7aRcFOA0sazeooa2wiJ9P9L31Mn5APZBJj5H8HjyKdvOmJ8neQn
 +b77Tya11Q70U57uDq69l0rl58fpy650uTwYaLNGWmUdTgOiGMWN05lvIVNrQd/R
 gP+VEQDGsTH6kqOCy9gyLCmn9q9I7l0t9lwcu5TP52Xy9vqVq9rb388MkcPcsWk8
 cYPvD8RcSaywZUV3YJgbYozBfVuf5rLVus6D54pMXe3N12KGaNBt8kk4co4jBwvh
 b//1urA82cdlEAZ/kiqHXjRMq/ht+dxtb6sSVOJ9frxPLuc7g1z4ORC+Z0PTS5WC
 zB0hMzPnTwXeqHcYpV4wP/vGtgZGpLevBkK7pKVdqKZykV8BS4FiT4HFp6Rghxs3
 dxAz7JjQUle6KOX7YfuHdpLnyZFWQvLYyTn946xGKpw2QH/iWLwECpet2I87QzVs
 QkEkGygPhK4QcGccxz9N
 =h5xk
 -----END PGP SIGNATURE-----

Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC platform updates from Olof Johansson:
 "New and/or improved SoC support for this release:

  Marvell Berlin:
     - Enable standard DT-based cpufreq
     - Add CPU hotplug support

  Freescale:
     - Ethernet init for i.MX7D
     - Suspend/resume support for i.MX6UL

  Allwinner:
     - Support for R8 chipset (used on NTC's $9 C.H.I.P board)

  Mediatek:
     - SMP support for some platforms

  Uniphier:
     - L2 support
     - Cleaned up SMP support, etc.

  plus a handful of other patches around above functionality, and a few
  other smaller changes"

* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (42 commits)
  ARM: uniphier: rework SMP operations to use trampoline code
  ARM: uniphier: add outer cache support
  Documentation: EXYNOS: Update bootloader interface on exynos542x
  ARM: mvebu: add broken-idle option
  ARM: orion5x: use mac_pton() helper
  ARM: at91: pm: at91_pm_suspend_in_sram() must be 8-byte aligned
  ARM: sunxi: Add R8 support
  ARM: digicolor: select pinctrl/gpio driver
  arm: berlin: add CPU hotplug support
  arm: berlin: use non-self-cleared reset register to reset cpu
  ARM: mediatek: add smp bringup code
  ARM: mediatek: enable gpt6 on boot up to make arch timer working
  soc: mediatek: Fix random hang up issue while kernel init
  soc: ti: qmss: make acc queue support optional in the driver
  soc: ti: add firmware file name as part of the driver
  Documentation: dt: soc: Add description for knav qmss driver
  ARM: S3C64XX: Use PWM lookup table for mach-smartq
  ARM: S3C64XX: Use PWM lookup table for mach-hmt
  ARM: S3C64XX: Use PWM lookup table for mach-crag6410
  ARM: S3C64XX: Use PWM lookup table for smdk6410
  ...
This commit is contained in:
Linus Torvalds 2015-11-10 14:56:23 -08:00
commit 56e0464980
70 changed files with 1888 additions and 296 deletions

View file

@ -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"

View file

@ -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/

View file

@ -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.

View file

@ -0,0 +1 @@
obj-y += common.o biuctrl.o

View file

@ -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 <linux/kernel.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
#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
}

View file

@ -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 <linux/of.h>
#include <soc/brcmstb/common.h>
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;
}

View file

@ -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);

View file

@ -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,8 @@ 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;
};
static const struct scp_domain_data scp_domain_data[] __initconst = {
@ -77,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",
@ -85,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",
@ -93,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",
@ -101,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,
},
@ -111,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",
@ -119,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",
@ -127,7 +132,8 @@ 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] = {
.name = "mfg_async",
@ -135,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",
@ -143,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",
@ -151,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 |
@ -166,12 +172,13 @@ 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;
u32 sram_pdn_ack_bits;
u32 bus_prot_mask;
bool active_wakeup;
};
struct scp {
@ -212,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);
@ -282,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);
@ -299,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,
@ -360,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;
@ -371,11 +387,22 @@ 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;
struct resource *res;
int i, ret;
int i, j, ret;
struct scp *scp;
struct clk *clk[MT8173_CLK_MAX];
@ -405,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)) {
@ -428,12 +463,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;
if (data->clk_id != MT8173_CLK_NONE)
scpd->clk = clk[data->clk_id];
scpd->active_wakeup = data->active_wakeup;
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;
genpd->power_on = scpsys_power_on;
genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
/*
* Initially turn on all domains to make the domains usable

View file

@ -135,9 +135,10 @@ struct knav_pdsp_info {
};
void __iomem *intd;
u32 __iomem *iram;
const char *firmware;
u32 id;
struct list_head list;
bool loaded;
bool started;
};
struct knav_qmgr_info {

View file

@ -486,8 +486,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;
@ -530,6 +530,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)) {

View file

@ -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;
}
@ -1510,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;
}
@ -1518,14 +1514,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;
@ -1583,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;
}