From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peng Fan Date: Wed, 18 Jul 2018 09:15:18 +0000 Subject: [U-Boot] [PATCH V2 07/32] misc: add i.MX8 misc driver In-Reply-To: References: <20180718013602.26574-1-peng.fan@nxp.com> <20180718013602.26574-8-peng.fan@nxp.com> <0b753334-e51f-bb88-5ea6-d13c1664d043@ti.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit To: u-boot@lists.denx.de > -----Original Message----- > From: Lokesh Vutla [mailto:lokeshvutla at ti.com] > Sent: 2018年7月18日 17:05 > To: Peng Fan ; sbabic at denx.de; Fabio Estevam > > Cc: u-boot at lists.denx.de; dl-linux-imx > Subject: Re: [U-Boot] [PATCH V2 07/32] misc: add i.MX8 misc driver > > > > On Wednesday 18 July 2018 02:22 PM, Peng Fan wrote: > > > > > >> -----Original Message----- > >> From: Lokesh Vutla [mailto:lokeshvutla at ti.com] > >> Sent: 2018年7月18日 16:38 > >> To: Peng Fan ; sbabic at denx.de; Fabio Estevam > >> > >> Cc: u-boot at lists.denx.de; dl-linux-imx > >> Subject: Re: [U-Boot] [PATCH V2 07/32] misc: add i.MX8 misc driver > >> > >> > >> > >> On Wednesday 18 July 2018 07:05 AM, Peng Fan wrote: > >>> Add i.MX8 MISC driver to handle the communication between > >>> A35 Core and SCU. > >> > >> > >> Ideally this is a good fit under drivers/remoteproc. Any reason why > >> UCLASS_REMOTEPROC is not considered? > > > > The SCU is booted by ROM, it provide services for other Cores. > > Nice. I agree that it provide services for other cores. I am trying to understand > how the communication happens. So you must be writing into a mailbox IP? > Then drivers/mailbox should be used to send and receive messages. Actually the communication is very simple, one message unit with 4 send register and 4 receive register. Use poll and no share memory involved. So only a few lines code in the low level communication part. Currently our device tree has not been merged into Linux upstream, NXP vendor tree use a simple mu node, no firmware node. In U-Boot, for simple, I not invent new firmware node, so I only has a mu node. With one node supporting mailbox/firmware dirver, this is not good. Considering the lowlevel communication is very simple in U-Boot, I directly merge the communication and protocol code in the driver/misc/imx8/*.c. In future when Linux community accepted i.MX8 device tree, I could sync and use a more clean implementation. Thanks, Peng. > > Thanks and regards, > Lokesh > > > It is not like rpmsg things. I think the misc driver is a good fit for > > my case. > > > > I also see that Tegra BPMP driver using misc driver. > > > > Thanks, > > Peng. > > > >> > >> Thanks and regards, > >> Lokesh > >> > >>> > >>> Signed-off-by: Peng Fan > >>> --- > >>> drivers/misc/Makefile | 1 + > >>> drivers/misc/imx8/Makefile | 3 + > >>> drivers/misc/imx8/scu.c | 247 > >> +++++++++++++++++++++++++++++++++++++++++++++ > >>> 3 files changed, 251 insertions(+) > >>> create mode 100644 drivers/misc/imx8/Makefile create mode 100644 > >>> drivers/misc/imx8/scu.c > >>> > >>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index > >>> 4ce9d213f0..c0de02c30d 100644 > >>> --- a/drivers/misc/Makefile > >>> +++ b/drivers/misc/Makefile > >>> @@ -6,6 +6,7 @@ > >>> obj-$(CONFIG_MISC) += misc-uclass.o > >>> obj-$(CONFIG_ALI152X) += ali512x.o > >>> obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o > >>> +obj-$(CONFIG_ARCH_IMX8) += imx8/ > >>> obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o > >>> obj-$(CONFIG_DS4510) += ds4510.o > >>> obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o diff --git > >>> a/drivers/misc/imx8/Makefile b/drivers/misc/imx8/Makefile new file > >>> mode 100644 index 0000000000..3395340d22 > >>> --- /dev/null > >>> +++ b/drivers/misc/imx8/Makefile > >> > >>> @@ -0,0 +1,3 @@ > >>> +# SPDX-License-Identifier: GPL-2.0+ > >>> + > >>> +obj-y += scu.o > >>> diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c new > >>> file mode 100644 index 0000000000..f12c7a96f2 > >>> --- /dev/null > >>> +++ b/drivers/misc/imx8/scu.c > >>> @@ -0,0 +1,247 @@ > >>> +// SPDX-License-Identifier: GPL-2.0 > >>> +/* > >>> + * Copyright 2018 NXP > >>> + * > >>> + * Peng Fan > >>> + */ > >>> + > >>> +#include > >>> +#include > >>> +#include > >>> +#include > >>> +#include > >>> +#include > >>> +#include > >>> +#include > >>> +#include > >>> + > >>> +DECLARE_GLOBAL_DATA_PTR; > >>> + > >>> +struct mu_type { > >>> + u32 tr[4]; > >>> + u32 rr[4]; > >>> + u32 sr; > >>> + u32 cr; > >>> +}; > >>> + > >>> +struct imx8_scu { > >>> + struct mu_type *base; > >>> + struct udevice *clk; > >>> + struct udevice *pinclk; > >>> +}; > >>> + > >>> +#define MU_CR_GIE_MASK 0xF0000000u > >>> +#define MU_CR_RIE_MASK 0xF000000u > >>> +#define MU_CR_GIR_MASK 0xF0000u > >>> +#define MU_CR_TIE_MASK 0xF00000u > >>> +#define MU_CR_F_MASK 0x7u > >>> +#define MU_SR_TE0_MASK BIT(23) > >>> +#define MU_SR_RF0_MASK BIT(27) > >>> +#define MU_TR_COUNT 4 > >>> +#define MU_RR_COUNT 4 > >>> +static inline void mu_hal_init(struct mu_type *base) { > >>> + /* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */ > >>> + clrbits_le32(&base->cr, MU_CR_GIE_MASK | MU_CR_RIE_MASK | > >>> + MU_CR_TIE_MASK | MU_CR_GIR_MASK | > MU_CR_F_MASK); } > >>> + > >>> +static int mu_hal_sendmsg(struct mu_type *base, u32 reg_index, u32 > >>> +msg) { > >>> + u32 mask = MU_SR_TE0_MASK >> reg_index; > >>> + u32 val; > >>> + int ret; > >>> + > >>> + assert(reg_index < MU_TR_COUNT); > >>> + > >>> + /* Wait TX register to be empty. */ > >>> + ret = readl_poll_timeout(&base->sr, val, val & mask, 10000); > >>> + if (ret < 0) { > >>> + printf("%s timeout\n", __func__); > >>> + return -ETIMEDOUT; > >>> + } > >>> + > >>> + writel(msg, &base->tr[reg_index]); > >>> + > >>> + return 0; > >>> +} > >>> + > >>> +static int mu_hal_receivemsg(struct mu_type *base, u32 reg_index, > >>> +u32 > >>> +*msg) { > >>> + u32 mask = MU_SR_RF0_MASK >> reg_index; > >>> + u32 val; > >>> + int ret; > >>> + > >>> + assert(reg_index < MU_TR_COUNT); > >>> + > >>> + /* Wait RX register to be full. */ > >>> + ret = readl_poll_timeout(&base->sr, val, val & mask, 10000); > >>> + if (ret < 0) { > >>> + printf("%s timeout\n", __func__); > >>> + return -ETIMEDOUT; > >>> + } > >>> + > >>> + *msg = readl(&base->rr[reg_index]); > >>> + > >>> + return 0; > >>> +} > >>> + > >>> +static void sc_ipc_read(struct mu_type *base, void *data) { > >>> + struct sc_rpc_msg_s *msg = (struct sc_rpc_msg_s *)data; > >>> + u8 count = 0; > >>> + > >>> + /* Check parms */ > >>> + if (!base || !msg) > >>> + return; > >>> + > >>> + /* Read first word */ > >>> + mu_hal_receivemsg(base, 0, (u32 *)msg); > >>> + count++; > >>> + > >>> + /* Check size */ > >>> + if (msg->size > SC_RPC_MAX_MSG) { > >>> + *((u32 *)msg) = 0; > >>> + return; > >>> + } > >>> + > >>> + /* Read remaining words */ > >>> + while (count < msg->size) { > >>> + mu_hal_receivemsg(base, count % MU_RR_COUNT, > >>> + &msg->DATA.u32[count - 1]); > >>> + count++; > >>> + } > >>> +} > >>> + > >>> +static void sc_ipc_write(struct mu_type *base, void *data) { > >>> + struct sc_rpc_msg_s *msg = (struct sc_rpc_msg_s *)data; > >>> + u8 count = 0; > >>> + > >>> + /* Check parms */ > >>> + if (!base || !msg) > >>> + return; > >>> + > >>> + /* Check size */ > >>> + if (msg->size > SC_RPC_MAX_MSG) > >>> + return; > >>> + > >>> + /* Write first word */ > >>> + mu_hal_sendmsg(base, 0, *((u32 *)msg)); > >>> + count++; > >>> + > >>> + /* Write remaining words */ > >>> + while (count < msg->size) { > >>> + mu_hal_sendmsg(base, count % MU_TR_COUNT, > >>> + msg->DATA.u32[count - 1]); > >>> + count++; > >>> + } > >>> +} > >>> + > >>> +/* > >>> + * Note the function prototype use msgid as the 2nd parameter, here > >>> + * we take it as no_resp. > >>> + */ > >>> +static int imx8_scu_call(struct udevice *dev, int no_resp, void *tx_msg, > >>> + int tx_size, void *rx_msg, int rx_size) { > >>> + struct imx8_scu *priv = dev_get_priv(dev); > >>> + sc_err_t result; > >>> + > >>> + /* Expect tx_msg, rx_msg are the same value */ > >>> + if (rx_msg && tx_msg != rx_msg) > >>> + printf("tx_msg %p, rx_msg %p\n", tx_msg, rx_msg); > >>> + > >>> + sc_ipc_write(priv->base, tx_msg); > >>> + if (!no_resp) > >>> + sc_ipc_read(priv->base, rx_msg); > >>> + > >>> + result = RPC_R8((sc_rpc_msg_t *)tx_msg); > >>> + > >>> + return sc_err_to_linux(result); > >>> +} > >>> + > >>> +static int imx8_scu_probe(struct udevice *dev) { > >>> + struct imx8_scu *priv = dev_get_priv(dev); > >>> + fdt_addr_t addr; > >>> + > >>> + debug("%s(dev=%p) (priv=%p)\n", __func__, dev, priv); > >>> + > >>> + addr = devfdt_get_addr(dev); > >>> + if (addr == FDT_ADDR_T_NONE) > >>> + return -EINVAL; > >>> + > >>> + priv->base = (struct mu_type *)addr; > >>> + > >>> + /* U-Boot not enable interrupts, so need to enable RX interrupts */ > >>> + mu_hal_init(priv->base); > >>> + > >>> + gd->arch.scu_dev = dev; > >>> + > >>> + device_probe(priv->clk); > >>> + device_probe(priv->pinclk); > >>> + > >>> + return 0; > >>> +} > >>> + > >>> +static int imx8_scu_remove(struct udevice *dev) { > >>> + return 0; > >>> +} > >>> + > >>> +static int imx8_scu_bind(struct udevice *dev) { > >>> + struct imx8_scu *priv = dev_get_priv(dev); > >>> + int ret; > >>> + struct udevice *child; > >>> + int node; > >>> + > >>> + debug("%s(dev=%p)\n", __func__, dev); > >>> + > >>> + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, > >>> + "fsl,imx8qxp-clk"); > >>> + if (node < 0) > >>> + panic("No clk node found\n"); > >>> + > >>> + ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child); > >>> + if (ret) > >>> + return ret; > >>> + > >>> + priv->clk = child; > >>> + > >>> + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, > >>> + "fsl,imx8qxp-iomuxc"); > >>> + if (node < 0) > >>> + panic("No clk node found\n"); > >>> + > >>> + ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child); > >>> + if (ret) > >>> + return ret; > >>> + > >>> + priv->pinclk = child; > >>> + > >>> + return 0; > >>> +} > >>> + > >>> +static struct misc_ops imx8_scu_ops = { > >>> + .call = imx8_scu_call, > >>> +}; > >>> + > >>> +static const struct udevice_id imx8_scu_ids[] = { > >>> + { .compatible = "fsl,imx8qxp-mu" }, > >>> + { .compatible = "fsl,imx8-mu" }, > >>> + { } > >>> +}; > >>> + > >>> +U_BOOT_DRIVER(imx8_scu) = { > >>> + .name = "imx8_scu", > >>> + .id = UCLASS_MISC, > >>> + .of_match = imx8_scu_ids, > >>> + .probe = imx8_scu_probe, > >>> + .bind = imx8_scu_bind, > >>> + .remove = imx8_scu_remove, > >>> + .ops = &imx8_scu_ops, > >>> + .priv_auto_alloc_size = sizeof(struct imx8_scu), > >>> + .flags = DM_FLAG_PRE_RELOC, > >>> +}; > >>>