Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f99552d9 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'imx-drivers-5.2' of...

Merge tag 'imx-drivers-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers

i.MX drivers change for 5.2:
 - A series from Aisheng to generalize the SCU powerdomain driver
   for easier adding new SCU based platforms like imx8qm.
 - Add a generic i.MX8 SoC driver for reporting SoC and platform
   information.
 - Replace explicit polling loop with a call to regmap_read_poll_timeout()
   for gpcv2 driver to avoid code repetition.
 - Use devm_platform_ioremap_resource() to simplify gpc/gpcv2 driver
   code a bit.
 - Add general IRQ support for imx-scu driver, so that interrupt of
   device like RTC, thermal and watchdog can be handled.

* tag 'imx-drivers-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux

:
  soc: imx: Add generic i.MX8 SoC driver
  firmware: imx: enable imx scu general irq function
  soc: imx: gpcv2: use devm_platform_ioremap_resource() to simplify code
  soc: imx: gpc: use devm_platform_ioremap_resource() to simplify code
  firmware: imx: scu-pd: decouple the SS information from domain names
  firmware: imx: scu-pd: add specifying the base of domain name index support
  firmware: imx: scu-pd: use bool to set postfix
  soc: imx: gpcv2: Make use of regmap_read_poll_timeout()

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents ab7b7c71 a7e26f35
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o
obj-$(CONFIG_IMX_SCU)		+= imx-scu.o misc.o imx-scu-irq.o
obj-$(CONFIG_IMX_SCU_PD)	+= scu-pd.o
+168 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2019 NXP
 *
 * Implementation of the SCU IRQ functions using MU.
 *
 */

#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/firmware/imx/ipc.h>
#include <linux/mailbox_client.h>

#define IMX_SC_IRQ_FUNC_ENABLE	1
#define IMX_SC_IRQ_FUNC_STATUS	2
#define IMX_SC_IRQ_NUM_GROUP	4

static u32 mu_resource_id;

struct imx_sc_msg_irq_get_status {
	struct imx_sc_rpc_msg hdr;
	union {
		struct {
			u16 resource;
			u8 group;
			u8 reserved;
		} __packed req;
		struct {
			u32 status;
		} resp;
	} data;
};

struct imx_sc_msg_irq_enable {
	struct imx_sc_rpc_msg hdr;
	u32 mask;
	u16 resource;
	u8 group;
	u8 enable;
} __packed;

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

int imx_scu_irq_register_notifier(struct notifier_block *nb)
{
	return atomic_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(
		&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,
		status, (void *)group);
}

static void imx_scu_irq_work_handler(struct work_struct *work)
{
	struct imx_sc_msg_irq_get_status msg;
	struct imx_sc_rpc_msg *hdr = &msg.hdr;
	u32 irq_status;
	int ret;
	u8 i;

	for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) {
		hdr->ver = IMX_SC_RPC_VERSION;
		hdr->svc = IMX_SC_RPC_SVC_IRQ;
		hdr->func = IMX_SC_IRQ_FUNC_STATUS;
		hdr->size = 2;

		msg.data.req.resource = mu_resource_id;
		msg.data.req.group = i;

		ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
		if (ret) {
			pr_err("get irq group %d status failed, ret %d\n",
			       i, ret);
			return;
		}

		irq_status = msg.data.resp.status;
		if (!irq_status)
			continue;

		imx_scu_irq_notifier_call_chain(irq_status, &i);
	}
}

int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
{
	struct imx_sc_msg_irq_enable msg;
	struct imx_sc_rpc_msg *hdr = &msg.hdr;
	int ret;

	hdr->ver = IMX_SC_RPC_VERSION;
	hdr->svc = IMX_SC_RPC_SVC_IRQ;
	hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
	hdr->size = 3;

	msg.resource = mu_resource_id;
	msg.group = group;
	msg.mask = mask;
	msg.enable = enable;

	ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
	if (ret)
		pr_err("enable irq failed, group %d, mask %d, ret %d\n",
			group, mask, ret);

	return ret;
}
EXPORT_SYMBOL(imx_scu_irq_group_enable);

static void imx_scu_irq_callback(struct mbox_client *c, void *msg)
{
	schedule_work(&imx_sc_irq_work);
}

int imx_scu_enable_general_irq_channel(struct device *dev)
{
	struct of_phandle_args spec;
	struct mbox_client *cl;
	struct mbox_chan *ch;
	int ret = 0, i = 0;

	ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle);
	if (ret)
		return ret;

	cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL);
	if (!cl)
		return -ENOMEM;

	cl->dev = dev;
	cl->rx_callback = imx_scu_irq_callback;

	/* SCU general IRQ uses general interrupt channel 3 */
	ch = mbox_request_channel_byname(cl, "gip3");
	if (IS_ERR(ch)) {
		ret = PTR_ERR(ch);
		dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret);
		devm_kfree(dev, cl);
		return ret;
	}

	INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);

	if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
				       "#mbox-cells", 0, &spec))
		i = of_alias_get_id(spec.np, "mu");

	/* use mu1 as general mu irq channel if failed */
	if (i < 0)
		i = 1;

	mu_resource_id = IMX_SC_R_MU_0A + i;

	return ret;
}
EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);
+6 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#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>
#include <linux/irq.h>
#include <linux/kernel.h>
@@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev)

	imx_sc_ipc_handle = sc_ipc;

	ret = imx_scu_enable_general_irq_channel(dev);
	if (ret)
		dev_warn(dev,
			"failed to enable general irq channel: %d\n", ret);

	dev_info(dev, "NXP i.MX SCU Initialized\n");

	return devm_of_platform_populate(dev);
+64 −57
Original line number Diff line number Diff line
@@ -74,7 +74,10 @@ struct imx_sc_pd_range {
	char *name;
	u32 rsrc;
	u8 num;

	/* add domain index */
	bool postfix;
	u8 start_from;
};

struct imx_sc_pd_soc {
@@ -84,71 +87,75 @@ struct imx_sc_pd_soc {

static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
	/* LSIO SS */
	{ "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 },
	{ "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 },
	{ "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 },
	{ "lsio-kpp", IMX_SC_R_KPP, 1, 0 },
	{ "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 },
	{ "lsio-mu", IMX_SC_R_MU_0A, 14, 1 },
	{ "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
	{ "gpio", IMX_SC_R_GPIO_0, 8, true, 0 },
	{ "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
	{ "kpp", IMX_SC_R_KPP, 1, false, 0 },
	{ "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
	{ "mu", IMX_SC_R_MU_0A, 14, true, 0 },

	/* CONN SS */
	{ "con-usb", IMX_SC_R_USB_0, 2, 1 },
	{ "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 },
	{ "con-usb2", IMX_SC_R_USB_2, 1, 0 },
	{ "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 },
	{ "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 },
	{ "con-enet", IMX_SC_R_ENET_0, 2, 1 },
	{ "con-nand", IMX_SC_R_NAND, 1, 0 },
	{ "con-mlb", IMX_SC_R_MLB_0, 1, 1 },

	/* Audio DMA SS */
	{ "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 },
	{ "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 },
	{ "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 },
	{ "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 },
	{ "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 },
	{ "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 },
	{ "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 },
	{ "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 },
	{ "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 },
	{ "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 },
	{ "adma-sai", IMX_SC_R_SAI_0, 3, 1 },
	{ "adma-amix", IMX_SC_R_AMIX, 1, 0 },
	{ "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 },
	{ "adma-dsp", IMX_SC_R_DSP, 1, 0 },
	{ "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 },
	{ "adma-can", IMX_SC_R_CAN_0, 3, 1 },
	{ "adma-ftm", IMX_SC_R_FTM_0, 2, 1 },
	{ "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 },
	{ "adma-adc", IMX_SC_R_ADC_0, 1, 1 },
	{ "adma-lcd", IMX_SC_R_LCD_0, 1, 1 },
	{ "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 },
	{ "adma-lpuart", IMX_SC_R_UART_0, 4, 1 },
	{ "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 },
	{ "usb", IMX_SC_R_USB_0, 2, true, 0 },
	{ "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
	{ "usb2", IMX_SC_R_USB_2, 1, false, 0 },
	{ "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
	{ "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
	{ "enet", IMX_SC_R_ENET_0, 2, true, 0 },
	{ "nand", IMX_SC_R_NAND, 1, false, 0 },
	{ "mlb", IMX_SC_R_MLB_0, 1, true, 0 },

	/* AUDIO SS */
	{ "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
	{ "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
	{ "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
	{ "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
	{ "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
	{ "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
	{ "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
	{ "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
	{ "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
	{ "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
	{ "sai", IMX_SC_R_SAI_0, 3, true, 0 },
	{ "amix", IMX_SC_R_AMIX, 1, false, 0 },
	{ "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
	{ "dsp", IMX_SC_R_DSP, 1, false, 0 },
	{ "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 },

	/* DMA SS */
	{ "can", IMX_SC_R_CAN_0, 3, true, 0 },
	{ "ftm", IMX_SC_R_FTM_0, 2, true, 0 },
	{ "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 },
	{ "adc", IMX_SC_R_ADC_0, 1, true, 0 },
	{ "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
	{ "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
	{ "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
	{ "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },

	/* VPU SS */
	{ "vpu", IMX_SC_R_VPU, 1, 0 },
	{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 },
	{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 },
	{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 },
	{ "vpu", IMX_SC_R_VPU, 1, false, 0 },
	{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
	{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
	{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },

	/* GPU SS */
	{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 },
	{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },

	/* HSIO SS */
	{ "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 },
	{ "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 },
	{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 },
	{ "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
	{ "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
	{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },

	/* MIPI SS */
	{ "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 },
	{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
	{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },

	/* MIPI/LVDS SS */
	{ "mipi0", IMX_SC_R_MIPI_0, 1, 0 },
	{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
	{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
	{ "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
	/* LVDS SS */
	{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },

	/* DC SS */
	{ "dc0", IMX_SC_R_DC_0, 1, 0 },
	{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 },
	{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },
	{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
};

static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
@@ -236,7 +243,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx,

	if (pd_ranges->postfix)
		snprintf(sc_pd->name, sizeof(sc_pd->name),
			 "%s%i", pd_ranges->name, idx);
			 "%s%i", pd_ranges->name, pd_ranges->start_from + idx);
	else
		snprintf(sc_pd->name, sizeof(sc_pd->name),
			 "%s", pd_ranges->name);
+1 −0
Original line number Diff line number Diff line
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
Loading