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

Commit bff00fdf authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

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

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

i.MX drivers update for 5.4:
 - A series from Anson Huang to add UID support for i.MX8 SoC and SCU
   drivers.
 - A series from Daniel Baluta to add DSP IPC driver for communication
   between host AP (Linux) and the firmware running on DSP embedded in
   i.MX8 SoCs.
 - A small fix for GPCv2 error code printing.
 - Switch from module_platform_driver_probe() to module_platform_driver()
   for imx-weim driver, as we need the driver to probe again when device
   is present later.
 - Add optional burst clock mode support for imx-weim driver.

* tag 'imx-drivers-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
  soc: imx: gpcv2: Print the correct error code
  bus: imx-weim: use module_platform_driver()
  firmware: imx: Add DSP IPC protocol interface
  soc: imx-scu: Add SoC UID(unique identifier) support
  bus: imx-weim: optionally enable burst clock mode
  firmware: imx: scu-pd: Add IRQSTR_DSP PD range
  firmware: imx: scu-pd: Add mu13 b side PD range
  firmware: imx: scu-pd: Rename mu PD range to mu_a
  soc: imx8: Add i.MX8MM UID(unique identifier) support
  soc: imx8: Add i.MX8MQ UID(unique identifier) support

Link: https://lore.kernel.org/r/20190825153237.28829-1-shawnguo@kernel.org


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 87288375 968c6f4b
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ struct imx_weim_devtype {
	unsigned int	cs_count;
	unsigned int	cs_regs_count;
	unsigned int	cs_stride;
	unsigned int	wcr_offset;
	unsigned int	wcr_bcm;
};

static const struct imx_weim_devtype imx1_weim_devtype = {
@@ -37,6 +39,8 @@ static const struct imx_weim_devtype imx50_weim_devtype = {
	.cs_count	= 4,
	.cs_regs_count	= 6,
	.cs_stride	= 0x18,
	.wcr_offset	= 0x90,
	.wcr_bcm	= BIT(0),
};

static const struct imx_weim_devtype imx51_weim_devtype = {
@@ -183,8 +187,7 @@ static int __init weim_timing_setup(struct device *dev,
	return 0;
}

static int __init weim_parse_dt(struct platform_device *pdev,
				void __iomem *base)
static int weim_parse_dt(struct platform_device *pdev, void __iomem *base)
{
	const struct of_device_id *of_id = of_match_device(weim_id_table,
							   &pdev->dev);
@@ -192,6 +195,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
	struct device_node *child;
	int ret, have_child = 0;
	struct cs_timing_state ts = {};
	u32 reg;

	if (devtype == &imx50_weim_devtype) {
		ret = imx_weim_gpr_setup(pdev);
@@ -199,6 +203,17 @@ static int __init weim_parse_dt(struct platform_device *pdev,
			return ret;
	}

	if (of_property_read_bool(pdev->dev.of_node, "fsl,burst-clk-enable")) {
		if (devtype->wcr_bcm) {
			reg = readl(base + devtype->wcr_offset);
			writel(reg | devtype->wcr_bcm,
				base + devtype->wcr_offset);
		} else {
			dev_err(&pdev->dev, "burst clk mode not supported.\n");
			return -EINVAL;
		}
	}

	for_each_available_child_of_node(pdev->dev.of_node, child) {
		ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts);
		if (ret)
@@ -217,7 +232,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
	return ret;
}

static int __init weim_probe(struct platform_device *pdev)
static int weim_probe(struct platform_device *pdev)
{
	struct resource *res;
	struct clk *clk;
@@ -254,8 +269,9 @@ static struct platform_driver weim_driver = {
		.name		= "imx-weim",
		.of_match_table	= weim_id_table,
	},
	.probe = weim_probe,
};
module_platform_driver_probe(weim_driver, weim_probe);
module_platform_driver(weim_driver);

MODULE_AUTHOR("Freescale Semiconductor Inc.");
MODULE_DESCRIPTION("i.MX EIM Controller Driver");
+11 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
config IMX_DSP
	bool "IMX DSP Protocol driver"
	depends on IMX_MBOX
	help
	  This enables DSP IPC protocol between host AP (Linux)
	  and the firmware running on DSP.
	  DSP exists on some i.MX8 processors (e.g i.MX8QM, i.MX8QXP).

	  It acts like a doorbell. Client might use shared memory to
	  exchange information with DSP side.

config IMX_SCU
	bool "IMX SCU Protocol driver"
	depends on IMX_MBOX
+1 −0
Original line number Diff line number Diff line
# 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_PD)	+= scu-pd.o
+155 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2019 NXP
 *  Author: Daniel Baluta <daniel.baluta@nxp.com>
 *
 * Implementation of the DSP IPC interface (host side)
 */

#include <linux/firmware/imx/dsp.h>
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

/*
 * imx_dsp_ring_doorbell - triggers an interrupt on the other side (DSP)
 *
 * @dsp: DSP IPC handle
 * @chan_idx: index of the channel where to trigger the interrupt
 *
 * Returns non-negative value for success, negative value for error
 */
int imx_dsp_ring_doorbell(struct imx_dsp_ipc *ipc, unsigned int idx)
{
	int ret;
	struct imx_dsp_chan *dsp_chan;

	if (idx >= DSP_MU_CHAN_NUM)
		return -EINVAL;

	dsp_chan = &ipc->chans[idx];
	ret = mbox_send_message(dsp_chan->ch, NULL);
	if (ret < 0)
		return ret;

	return 0;
}
EXPORT_SYMBOL(imx_dsp_ring_doorbell);

/*
 * imx_dsp_handle_rx - rx callback used by imx mailbox
 *
 * @c: mbox client
 * @msg: message received
 *
 * Users of DSP IPC will need to privde handle_reply and handle_request
 * callbacks.
 */
static void imx_dsp_handle_rx(struct mbox_client *c, void *msg)
{
	struct imx_dsp_chan *chan = container_of(c, struct imx_dsp_chan, cl);

	if (chan->idx == 0) {
		chan->ipc->ops->handle_reply(chan->ipc);
	} else {
		chan->ipc->ops->handle_request(chan->ipc);
		imx_dsp_ring_doorbell(chan->ipc, 1);
	}
}

static int imx_dsp_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct imx_dsp_ipc *dsp_ipc;
	struct imx_dsp_chan *dsp_chan;
	struct mbox_client *cl;
	char *chan_name;
	int ret;
	int i, j;

	device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);

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

	for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
		if (i < 2)
			chan_name = kasprintf(GFP_KERNEL, "txdb%d", i);
		else
			chan_name = kasprintf(GFP_KERNEL, "rxdb%d", i - 2);

		if (!chan_name)
			return -ENOMEM;

		dsp_chan = &dsp_ipc->chans[i];
		cl = &dsp_chan->cl;
		cl->dev = dev;
		cl->tx_block = false;
		cl->knows_txdone = true;
		cl->rx_callback = imx_dsp_handle_rx;

		dsp_chan->ipc = dsp_ipc;
		dsp_chan->idx = i % 2;
		dsp_chan->ch = mbox_request_channel_byname(cl, chan_name);
		if (IS_ERR(dsp_chan->ch)) {
			ret = PTR_ERR(dsp_chan->ch);
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "Failed to request mbox chan %s ret %d\n",
					chan_name, ret);
			goto out;
		}

		dev_dbg(dev, "request mbox chan %s\n", chan_name);
		/* chan_name is not used anymore by framework */
		kfree(chan_name);
	}

	dsp_ipc->dev = dev;

	dev_set_drvdata(dev, dsp_ipc);

	dev_info(dev, "NXP i.MX DSP IPC initialized\n");

	return devm_of_platform_populate(dev);
out:
	kfree(chan_name);
	for (j = 0; j < i; j++) {
		dsp_chan = &dsp_ipc->chans[j];
		mbox_free_channel(dsp_chan->ch);
	}

	return ret;
}

static int imx_dsp_remove(struct platform_device *pdev)
{
	struct imx_dsp_chan *dsp_chan;
	struct imx_dsp_ipc *dsp_ipc;
	int i;

	dsp_ipc = dev_get_drvdata(&pdev->dev);

	for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
		dsp_chan = &dsp_ipc->chans[i];
		mbox_free_channel(dsp_chan->ch);
	}

	return 0;
}

static struct platform_driver imx_dsp_driver = {
	.driver = {
		.name = "imx-dsp",
	},
	.probe = imx_dsp_probe,
	.remove = imx_dsp_remove,
};
builtin_platform_driver(imx_dsp_driver);

MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
MODULE_DESCRIPTION("IMX DSP IPC protocol driver");
MODULE_LICENSE("GPL v2");
+3 −1
Original line number Diff line number Diff line
@@ -92,7 +92,8 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
	{ "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 },
	{ "mu_a", IMX_SC_R_MU_0A, 14, true, 0 },
	{ "mu_b", IMX_SC_R_MU_13B, 1, true, 13 },

	/* CONN SS */
	{ "usb", IMX_SC_R_USB_0, 2, true, 0 },
@@ -130,6 +131,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
	{ "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 },
	{ "irqstr_dsp", IMX_SC_R_IRQSTR_DSP, 1, false, 0 },

	/* VPU SS */
	{ "vpu", IMX_SC_R_VPU, 1, false, 0 },
Loading