Merge branch 'firmware/next' into next

* firmware/next: (15 commits)
  firmware: imx: Allow imx dsp to be selected as module
  LF-202-4 firmware: imx: scu-pd: ignore power domain not owned
  LF-202-2 firmware: imx: add resource management api
  LF-202-1 firmware: imx: scu: use hvc for dom0
  MLK-22984 firmware: imx: imx-scu-irq: fix RCU complains after M4 partition reset
  ...
This commit is contained in:
Dong Aisheng 2019-12-02 18:02:26 +08:00
commit 74c70feb09
12 changed files with 282 additions and 91 deletions

View File

@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config IMX_DSP
bool "IMX DSP Protocol driver"
tristate "IMX DSP Protocol driver"
depends on IMX_MBOX
help
This enables DSP IPC protocol between host AP (Linux)

View File

@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_IMX_DSP) += imx-dsp.o
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o
obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o

View File

@ -9,10 +9,11 @@
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/firmware/imx/ipc.h>
#include <linux/mailbox_client.h>
#include <linux/suspend.h>
#define IMX_SC_IRQ_FUNC_ENABLE 1
#define IMX_SC_IRQ_FUNC_STATUS 2
#define IMX_SC_IRQ_NUM_GROUP 4
#define IMX_SC_IRQ_NUM_GROUP 7
static u32 mu_resource_id;
@ -40,25 +41,25 @@ struct imx_sc_msg_irq_enable {
static struct imx_sc_ipc *imx_sc_irq_ipc_handle;
static struct work_struct imx_sc_irq_work;
static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
static BLOCKING_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
int imx_scu_irq_register_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(
return blocking_notifier_chain_register(
&imx_scu_irq_notifier_chain, nb);
}
EXPORT_SYMBOL(imx_scu_irq_register_notifier);
int imx_scu_irq_unregister_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(
return blocking_notifier_chain_unregister(
&imx_scu_irq_notifier_chain, nb);
}
EXPORT_SYMBOL(imx_scu_irq_unregister_notifier);
static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group)
{
return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain,
return blocking_notifier_call_chain(&imx_scu_irq_notifier_chain,
status, (void *)group);
}
@ -90,6 +91,7 @@ static void imx_scu_irq_work_handler(struct work_struct *work)
if (!irq_status)
continue;
pm_system_wakeup();
imx_scu_irq_notifier_call_chain(irq_status, &i);
}
}

View File

@ -7,8 +7,8 @@
*
*/
#include <linux/arm-smccc.h>
#include <linux/err.h>
#include <linux/firmware/imx/types.h>
#include <linux/firmware/imx/ipc.h>
#include <linux/firmware/imx/sci.h>
#include <linux/interrupt.h>
@ -20,8 +20,11 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <xen/xen.h>
#define FSL_HVC_SC 0xC6000000
#define SCU_MU_CHAN_NUM 8
#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000))
struct imx_sc_chan {
struct imx_sc_ipc *sc_ipc;
@ -157,6 +160,7 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
{
struct imx_sc_rpc_msg *hdr;
struct arm_smccc_res res;
int ret;
if (WARN_ON(!sc_ipc || !msg))
@ -167,23 +171,34 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
sc_ipc->msg = msg;
sc_ipc->count = 0;
ret = imx_scu_ipc_write(sc_ipc, msg);
if (ret < 0) {
dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret);
goto out;
}
sc_ipc->rx_size = 0;
if (xen_initial_domain()) {
arm_smccc_hvc(FSL_HVC_SC, (uint64_t)msg, !have_resp, 0, 0, 0,
0, 0, &res);
if (res.a0)
printk("Error FSL_HVC_SC %ld\n", res.a0);
if (have_resp) {
if (!wait_for_completion_timeout(&sc_ipc->done,
MAX_RX_TIMEOUT)) {
dev_err(sc_ipc->dev, "RPC send msg timeout\n");
mutex_unlock(&sc_ipc->lock);
return -ETIMEDOUT;
ret = res.a0;
} else {
ret = imx_scu_ipc_write(sc_ipc, msg);
if (ret < 0) {
dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret);
goto out;
}
/* response status is stored in hdr->func field */
hdr = msg;
ret = hdr->func;
if (have_resp) {
if (!wait_for_completion_timeout(&sc_ipc->done,
MAX_RX_TIMEOUT)) {
dev_err(sc_ipc->dev, "RPC send msg timeout\n");
mutex_unlock(&sc_ipc->lock);
return -ETIMEDOUT;
}
/* response status is stored in hdr->func field */
hdr = msg;
ret = hdr->func;
}
}
out:
@ -269,7 +284,12 @@ static struct platform_driver imx_scu_driver = {
},
.probe = imx_scu_probe,
};
builtin_platform_driver(imx_scu_driver);
static int __init imx_scu_driver_init(void)
{
return platform_driver_register(&imx_scu_driver);
}
subsys_initcall_sync(imx_scu_driver_init);
MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
MODULE_DESCRIPTION("IMX SCU firmware protocol driver");

41
drivers/firmware/imx/rm.c Normal file
View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017~2019 NXP
*
* File containing client-side RPC functions for the RM service. These
* function are ported to clients that communicate to the SC.
*/
#include <linux/firmware/imx/svc/rm.h>
struct imx_sc_msg_rm_rsrc_owned {
struct imx_sc_rpc_msg hdr;
u16 resource;
} __packed __aligned(4);
/*
* This function check @resource is owned by current partition or not
*
* @param[in] ipc IPC handle
* @param[in] resource resource the control is associated with
*
* @return Returns 0 for success and < 0 for errors.
*/
bool imx_sc_rm_is_resource_owned(struct imx_sc_ipc *ipc, u16 resource)
{
struct imx_sc_msg_rm_rsrc_owned msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_RM;
hdr->func = IMX_SC_RM_FUNC_IS_RESOURCE_OWNED;
hdr->size = 2;
msg.resource = resource;
imx_scu_call_rpc(ipc, &msg, true);
return hdr->func;
}
EXPORT_SYMBOL(imx_sc_rm_is_resource_owned);

View File

@ -46,6 +46,7 @@
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/firmware/imx/sci.h>
#include <linux/firmware/imx/svc/rm.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@ -155,6 +156,11 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
/* LVDS SS */
{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
{ "mipi1", IMX_SC_R_MIPI_1, 1, 0 },
{ "mipi1-pwm0", IMX_SC_R_MIPI_1_PWM_0, 1, 0 },
{ "mipi1-i2c", IMX_SC_R_MIPI_1_I2C_0, 2, 1 },
{ "lvds1", IMX_SC_R_LVDS_1, 1, 0 },
/* DC SS */
{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
@ -195,6 +201,14 @@ static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on)
dev_err(&domain->dev, "failed to power %s resource %d ret %d\n",
power_on ? "up" : "off", pd->rsrc, ret);
/* keep HDMI TX resource power on */
if (power_on && (pd->rsrc == IMX_SC_R_HDMI ||
pd->rsrc == IMX_SC_R_HDMI_I2S ||
pd->rsrc == IMX_SC_R_HDMI_I2C_0 ||
pd->rsrc == IMX_SC_R_HDMI_PLL_0 ||
pd->rsrc == IMX_SC_R_HDMI_PLL_1))
pd->pd.flags |= GENPD_FLAG_ALWAYS_ON;
return ret;
}
@ -235,6 +249,9 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
struct imx_sc_pm_domain *sc_pd;
int ret;
if (!imx_sc_rm_is_resource_owned(pm_ipc_handle, pd_ranges->rsrc + idx))
return NULL;
sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
if (!sc_pd)
return ERR_PTR(-ENOMEM);

View File

@ -547,4 +547,82 @@
#define IMX_SC_R_ATTESTATION 545
#define IMX_SC_R_LAST 546
/*
* Defines for SC PM CLK
*/
#define IMX_SC_PM_CLK_SLV_BUS 0 /* Slave bus clock */
#define IMX_SC_PM_CLK_MST_BUS 1 /* Master bus clock */
#define IMX_SC_PM_CLK_PER 2 /* Peripheral clock */
#define IMX_SC_PM_CLK_PHY 3 /* Phy clock */
#define IMX_SC_PM_CLK_MISC 4 /* Misc clock */
#define IMX_SC_PM_CLK_MISC0 0 /* Misc 0 clock */
#define IMX_SC_PM_CLK_MISC1 1 /* Misc 1 clock */
#define IMX_SC_PM_CLK_MISC2 2 /* Misc 2 clock */
#define IMX_SC_PM_CLK_MISC3 3 /* Misc 3 clock */
#define IMX_SC_PM_CLK_MISC4 4 /* Misc 4 clock */
#define IMX_SC_PM_CLK_CPU 2 /* CPU clock */
#define IMX_SC_PM_CLK_PLL 4 /* PLL */
#define IMX_SC_PM_CLK_BYPASS 4 /* Bypass clock */
/*!
* Defines for sc_ctrl_t.
*/
#define IMX_SC_C_TEMP 0U
#define IMX_SC_C_TEMP_HI 1U
#define IMX_SC_C_TEMP_LOW 2U
#define IMX_SC_C_PXL_LINK_MST1_ADDR 3U
#define IMX_SC_C_PXL_LINK_MST2_ADDR 4U
#define IMX_SC_C_PXL_LINK_MST_ENB 5U
#define IMX_SC_C_PXL_LINK_MST1_ENB 6U
#define IMX_SC_C_PXL_LINK_MST2_ENB 7U
#define IMX_SC_C_PXL_LINK_SLV1_ADDR 8U
#define IMX_SC_C_PXL_LINK_SLV2_ADDR 9U
#define IMX_SC_C_PXL_LINK_MST_VLD 10U
#define IMX_SC_C_PXL_LINK_MST1_VLD 11U
#define IMX_SC_C_PXL_LINK_MST2_VLD 12U
#define IMX_SC_C_SINGLE_MODE 13U
#define IMX_SC_C_ID 14U
#define IMX_SC_C_PXL_CLK_POLARITY 15U
#define IMX_SC_C_LINESTATE 16U
#define IMX_SC_C_PCIE_G_RST 17U
#define IMX_SC_C_PCIE_BUTTON_RST 18U
#define IMX_SC_C_PCIE_PERST 19U
#define IMX_SC_C_PHY_RESET 20U
#define IMX_SC_C_PXL_LINK_RATE_CORRECTION 21U
#define IMX_SC_C_PANIC 22U
#define IMX_SC_C_PRIORITY_GROUP 23U
#define IMX_SC_C_TXCLK 24U
#define IMX_SC_C_CLKDIV 25U
#define IMX_SC_C_DISABLE_50 26U
#define IMX_SC_C_DISABLE_125 27U
#define IMX_SC_C_SEL_125 28U
#define IMX_SC_C_MODE 29U
#define IMX_SC_C_SYNC_CTRL0 30U
#define IMX_SC_C_KACHUNK_CNT 31U
#define IMX_SC_C_KACHUNK_SEL 32U
#define IMX_SC_C_SYNC_CTRL1 33U
#define IMX_SC_C_DPI_RESET 34U
#define IMX_SC_C_MIPI_RESET 35U
#define IMX_SC_C_DUAL_MODE 36U
#define IMX_SC_C_VOLTAGE 37U
#define IMX_SC_C_PXL_LINK_SEL 38U
#define IMX_SC_C_OFS_SEL 39U
#define IMX_SC_C_OFS_AUDIO 40U
#define IMX_SC_C_OFS_PERIPH 41U
#define IMX_SC_C_OFS_IRQ 42U
#define IMX_SC_C_RST0 43U
#define IMX_SC_C_RST1 44U
#define IMX_SC_C_SEL0 45U
#define IMX_SC_C_CALIB0 46U
#define IMX_SC_C_CALIB1 47U
#define IMX_SC_C_CALIB2 48U
#define IMX_SC_C_IPG_DEBUG 49U
#define IMX_SC_C_IPG_DOZE 50U
#define IMX_SC_C_IPG_WAIT 51U
#define IMX_SC_C_IPG_STOP 52U
#define IMX_SC_C_IPG_STOP_MODE 53U
#define IMX_SC_C_IPG_STOP_ACK 54U
#define IMX_SC_C_SYNC_CTRL 55U
#define IMX_SC_C_LAST 56U
#endif /* __DT_BINDINGS_RSCRC_IMX_H */

View File

@ -9,7 +9,6 @@
#define _SC_IPC_H
#include <linux/device.h>
#include <linux/types.h>
#define IMX_SC_RPC_VERSION 1
#define IMX_SC_RPC_MAX_MSG 8
@ -35,6 +34,7 @@ struct imx_sc_rpc_msg {
uint8_t func;
};
#if IS_ENABLED(CONFIG_IMX_SCU)
/*
* This is an function to send an RPC message over an IPC channel.
* It is called by client-side SCFW API function shims.
@ -56,4 +56,17 @@ int imx_scu_call_rpc(struct imx_sc_ipc *ipc, void *msg, bool have_resp);
* @return Returns an error code (0 = success, failed if < 0)
*/
int imx_scu_get_handle(struct imx_sc_ipc **ipc);
#else
static inline int
imx_scu_call_rpc(struct imx_sc_ipc *ipc, void *msg, bool have_resp)
{
return -EIO;
}
static inline int imx_scu_get_handle(struct imx_sc_ipc **ipc)
{
return -EIO;
}
#endif
#endif /* _SC_IPC_H */

View File

@ -11,10 +11,10 @@
#define _SC_SCI_H
#include <linux/firmware/imx/ipc.h>
#include <linux/firmware/imx/types.h>
#include <linux/firmware/imx/svc/misc.h>
#include <linux/firmware/imx/svc/pm.h>
#include <linux/firmware/imx/svc/rm.h>
int imx_scu_enable_general_irq_channel(struct device *dev);
int imx_scu_irq_register_notifier(struct notifier_block *nb);

View File

@ -46,11 +46,27 @@ enum imx_misc_func {
* Control Functions
*/
#if IS_ENABLED(CONFIG_IMX_SCU)
int imx_sc_misc_set_control(struct imx_sc_ipc *ipc, u32 resource,
u8 ctrl, u32 val);
int imx_sc_misc_get_control(struct imx_sc_ipc *ipc, u32 resource,
u8 ctrl, u32 *val);
#else
static inline int
imx_sc_misc_set_control(struct imx_sc_ipc *ipc, u32 resource,
u8 ctrl, u32 val)
{
return -EIO;
}
static inline int
imx_sc_misc_get_control(struct imx_sc_ipc *ipc, u32 resource,
u8 ctrl, u32 *val)
{
return -EIO;
}
#endif
int imx_sc_pm_cpu_start(struct imx_sc_ipc *ipc, u32 resource,
bool enable, u64 phys_addr);

View File

@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017-2019 NXP
*
* Header file containing the public API for the System Controller (SC)
* Power Management (PM) function. This includes functions for power state
* control, clock control, reset control, and wake-up event control.
*
* RM_SVC (SVC) Resource Management Service
*
* Module for the Resource Management (RM) service.
*/
#ifndef _SC_RM_API_H
#define _SC_RM_API_H
#include <linux/firmware/imx/sci.h>
/*
* This type is used to indicate RPC RM function calls.
*/
enum imx_sc_rm_func {
IMX_SC_RM_FUNC_UNKNOWN = 0,
IMX_SC_RM_FUNC_PARTITION_ALLOC = 1,
IMX_SC_RM_FUNC_SET_CONFIDENTIAL = 31,
IMX_SC_RM_FUNC_PARTITION_FREE = 2,
IMX_SC_RM_FUNC_GET_DID = 26,
IMX_SC_RM_FUNC_PARTITION_STATIC = 3,
IMX_SC_RM_FUNC_PARTITION_LOCK = 4,
IMX_SC_RM_FUNC_GET_PARTITION = 5,
IMX_SC_RM_FUNC_SET_PARENT = 6,
IMX_SC_RM_FUNC_MOVE_ALL = 7,
IMX_SC_RM_FUNC_ASSIGN_RESOURCE = 8,
IMX_SC_RM_FUNC_SET_RESOURCE_MOVABLE = 9,
IMX_SC_RM_FUNC_SET_SUBSYS_RSRC_MOVABLE = 28,
IMX_SC_RM_FUNC_SET_MASTER_ATTRIBUTES = 10,
IMX_SC_RM_FUNC_SET_MASTER_SID = 11,
IMX_SC_RM_FUNC_SET_PERIPHERAL_PERMISSIONS = 12,
IMX_SC_RM_FUNC_IS_RESOURCE_OWNED = 13,
IMX_SC_RM_FUNC_GET_RESOURCE_OWNER = 33,
IMX_SC_RM_FUNC_IS_RESOURCE_MASTER = 14,
IMX_SC_RM_FUNC_IS_RESOURCE_PERIPHERAL = 15,
IMX_SC_RM_FUNC_GET_RESOURCE_INFO = 16,
IMX_SC_RM_FUNC_MEMREG_ALLOC = 17,
IMX_SC_RM_FUNC_MEMREG_SPLIT = 29,
IMX_SC_RM_FUNC_MEMREG_FRAG = 32,
IMX_SC_RM_FUNC_MEMREG_FREE = 18,
IMX_SC_RM_FUNC_FIND_MEMREG = 30,
IMX_SC_RM_FUNC_ASSIGN_MEMREG = 19,
IMX_SC_RM_FUNC_SET_MEMREG_PERMISSIONS = 20,
IMX_SC_RM_FUNC_IS_MEMREG_OWNED = 21,
IMX_SC_RM_FUNC_GET_MEMREG_INFO = 22,
IMX_SC_RM_FUNC_ASSIGN_PAD = 23,
IMX_SC_RM_FUNC_SET_PAD_MOVABLE = 24,
IMX_SC_RM_FUNC_IS_PAD_OWNED = 25,
IMX_SC_RM_FUNC_DUMP = 27,
};
#if IS_ENABLED(CONFIG_IMX_SCU)
bool imx_sc_rm_is_resource_owned(struct imx_sc_ipc *ipc, u16 resource);
#else
static inline bool
imx_sc_rm_is_resource_owned(struct imx_sc_ipc *ipc, u16 resource)
{
return true;
}
#endif
#endif

View File

@ -1,65 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017~2018 NXP
*
* Header file containing types used across multiple service APIs.
*/
#ifndef _SC_TYPES_H
#define _SC_TYPES_H
/*
* This type is used to indicate a control.
*/
enum imx_sc_ctrl {
IMX_SC_C_TEMP = 0,
IMX_SC_C_TEMP_HI = 1,
IMX_SC_C_TEMP_LOW = 2,
IMX_SC_C_PXL_LINK_MST1_ADDR = 3,
IMX_SC_C_PXL_LINK_MST2_ADDR = 4,
IMX_SC_C_PXL_LINK_MST_ENB = 5,
IMX_SC_C_PXL_LINK_MST1_ENB = 6,
IMX_SC_C_PXL_LINK_MST2_ENB = 7,
IMX_SC_C_PXL_LINK_SLV1_ADDR = 8,
IMX_SC_C_PXL_LINK_SLV2_ADDR = 9,
IMX_SC_C_PXL_LINK_MST_VLD = 10,
IMX_SC_C_PXL_LINK_MST1_VLD = 11,
IMX_SC_C_PXL_LINK_MST2_VLD = 12,
IMX_SC_C_SINGLE_MODE = 13,
IMX_SC_C_ID = 14,
IMX_SC_C_PXL_CLK_POLARITY = 15,
IMX_SC_C_LINESTATE = 16,
IMX_SC_C_PCIE_G_RST = 17,
IMX_SC_C_PCIE_BUTTON_RST = 18,
IMX_SC_C_PCIE_PERST = 19,
IMX_SC_C_PHY_RESET = 20,
IMX_SC_C_PXL_LINK_RATE_CORRECTION = 21,
IMX_SC_C_PANIC = 22,
IMX_SC_C_PRIORITY_GROUP = 23,
IMX_SC_C_TXCLK = 24,
IMX_SC_C_CLKDIV = 25,
IMX_SC_C_DISABLE_50 = 26,
IMX_SC_C_DISABLE_125 = 27,
IMX_SC_C_SEL_125 = 28,
IMX_SC_C_MODE = 29,
IMX_SC_C_SYNC_CTRL0 = 30,
IMX_SC_C_KACHUNK_CNT = 31,
IMX_SC_C_KACHUNK_SEL = 32,
IMX_SC_C_SYNC_CTRL1 = 33,
IMX_SC_C_DPI_RESET = 34,
IMX_SC_C_MIPI_RESET = 35,
IMX_SC_C_DUAL_MODE = 36,
IMX_SC_C_VOLTAGE = 37,
IMX_SC_C_PXL_LINK_SEL = 38,
IMX_SC_C_OFS_SEL = 39,
IMX_SC_C_OFS_AUDIO = 40,
IMX_SC_C_OFS_PERIPH = 41,
IMX_SC_C_OFS_IRQ = 42,
IMX_SC_C_RST0 = 43,
IMX_SC_C_RST1 = 44,
IMX_SC_C_SEL0 = 45,
IMX_SC_C_LAST
};
#endif /* _SC_TYPES_H */