mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 18:35:42 +01:00 
			
		
		
		
	mailbox: zynqmp: ipi mailbox driver
ZynqMP mailbox driver implementing IPI communication with PMU. This would allow U-Boot SPL to communicate with PMUFW to request privileged operations. Signed-off-by: Ibai Erkiaga <ibai.erkiaga-elorza@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
This commit is contained in:
		
				
					committed by
					
						 Michal Simek
						Michal Simek
					
				
			
			
				
	
			
			
			
						parent
						
							05f683a3e2
						
					
				
				
					commit
					660b0c77d8
				
			| @@ -449,6 +449,7 @@ F:	drivers/gpio/zynq_gpio.c | ||||
| F:	drivers/i2c/i2c-cdns.c | ||||
| F:	drivers/i2c/muxes/pca954x.c | ||||
| F:	drivers/i2c/zynq_i2c.c | ||||
| F:	drivers/mailbox/zynqmp-ipi.c | ||||
| F:	drivers/mmc/zynq_sdhci.c | ||||
| F:	drivers/mtd/nand/raw/zynq_nand.c | ||||
| F:	drivers/net/phy/xilinx_phy.c | ||||
|   | ||||
| @@ -54,6 +54,11 @@ enum { | ||||
| 	TCM_SPLIT, | ||||
| }; | ||||
|  | ||||
| struct zynqmp_ipi_msg { | ||||
| 	size_t len; | ||||
| 	u32 *buf; | ||||
| }; | ||||
|  | ||||
| int zynq_board_read_rom_ethaddr(unsigned char *ethaddr); | ||||
| unsigned int zynqmp_get_silicon_version(void); | ||||
|  | ||||
|   | ||||
| @@ -41,4 +41,10 @@ config K3_SEC_PROXY | ||||
| 	  Select this driver if your platform has support for this hardware | ||||
| 	  block. | ||||
|  | ||||
| config ZYNQMP_IPI | ||||
| 	bool "Xilinx ZynqMP IPI controller support" | ||||
| 	depends on DM_MAILBOX && ARCH_ZYNQMP | ||||
| 	help | ||||
| 	  This enables support for the Xilinx ZynqMP Inter Processor Interrupt | ||||
| 	  communication controller. | ||||
| endmenu | ||||
|   | ||||
| @@ -9,3 +9,4 @@ obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o | ||||
| obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o | ||||
| obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o | ||||
| obj-$(CONFIG_K3_SEC_PROXY) += k3-sec-proxy.o | ||||
| obj-$(CONFIG_ZYNQMP_IPI) += zynqmp-ipi.o | ||||
|   | ||||
							
								
								
									
										134
									
								
								drivers/mailbox/zynqmp-ipi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								drivers/mailbox/zynqmp-ipi.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Xilinx Zynq MPSoC Mailbox driver | ||||
|  * | ||||
|  * Copyright (C) 2018-2019 Xilinx, Inc. | ||||
|  */ | ||||
|  | ||||
| #include <common.h> | ||||
| #include <asm/io.h> | ||||
| #include <dm.h> | ||||
| #include <mailbox-uclass.h> | ||||
| #include <mach/sys_proto.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/io.h> | ||||
| #include <wait_bit.h> | ||||
|  | ||||
| /* IPI bitmasks, register base */ | ||||
| /* TODO: move reg base to DT */ | ||||
| #define IPI_BIT_MASK_PMU0     0x10000 | ||||
| #define IPI_INT_REG_BASE_APU  0xFF300000 | ||||
|  | ||||
| struct ipi_int_regs { | ||||
| 	u32 trig; /* 0x0  */ | ||||
| 	u32 obs;  /* 0x4  */ | ||||
| 	u32 ist;  /* 0x8  */ | ||||
| 	u32 imr;  /* 0xC  */ | ||||
| 	u32 ier;  /* 0x10 */ | ||||
| 	u32 idr;  /* 0x14 */ | ||||
| }; | ||||
|  | ||||
| #define ipi_int_apu ((struct ipi_int_regs *)IPI_INT_REG_BASE_APU) | ||||
|  | ||||
| struct zynqmp_ipi { | ||||
| 	void __iomem *local_req_regs; | ||||
| 	void __iomem *local_res_regs; | ||||
| 	void __iomem *remote_req_regs; | ||||
| 	void __iomem *remote_res_regs; | ||||
| }; | ||||
|  | ||||
| static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data) | ||||
| { | ||||
| 	const struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data; | ||||
| 	struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev); | ||||
| 	u32 ret; | ||||
| 	u32 *mbx = (u32 *)zynqmp->local_req_regs; | ||||
|  | ||||
| 	for (size_t i = 0; i < msg->len; i++) | ||||
| 		writel(msg->buf[i], &mbx[i]); | ||||
|  | ||||
| 	/* Write trigger interrupt */ | ||||
| 	writel(IPI_BIT_MASK_PMU0, &ipi_int_apu->trig); | ||||
|  | ||||
| 	/* Wait until observation bit is cleared */ | ||||
| 	ret = wait_for_bit_le32(&ipi_int_apu->obs, IPI_BIT_MASK_PMU0, false, | ||||
| 				100, false); | ||||
|  | ||||
| 	debug("%s, send %ld bytes\n", __func__, msg->len); | ||||
| 	return ret; | ||||
| }; | ||||
|  | ||||
| static int zynqmp_ipi_recv(struct mbox_chan *chan, void *data) | ||||
| { | ||||
| 	struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data; | ||||
| 	struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev); | ||||
| 	u32 *mbx = (u32 *)zynqmp->local_res_regs; | ||||
|  | ||||
| 	for (size_t i = 0; i < msg->len; i++) | ||||
| 		msg->buf[i] = readl(&mbx[i]); | ||||
|  | ||||
| 	debug("%s, recv %ld bytes\n", __func__, msg->len); | ||||
| 	return 0; | ||||
| }; | ||||
|  | ||||
| static int zynqmp_ipi_probe(struct udevice *dev) | ||||
| { | ||||
| 	struct zynqmp_ipi *zynqmp = dev_get_priv(dev); | ||||
| 	struct resource res; | ||||
| 	ofnode node; | ||||
|  | ||||
| 	debug("%s(dev=%p)\n", __func__, dev); | ||||
|  | ||||
| 	/* Get subnode where the regs are defined */ | ||||
| 	/* Note IPI mailbox node needs to be the first one in DT */ | ||||
| 	node = ofnode_first_subnode(dev_ofnode(dev)); | ||||
|  | ||||
| 	if (ofnode_read_resource_byname(node, "local_request_region", &res)) { | ||||
| 		dev_err(dev, "No reg property for local_request_region\n"); | ||||
| 		return -EINVAL; | ||||
| 	}; | ||||
| 	zynqmp->local_req_regs = devm_ioremap(dev, res.start, | ||||
| 					      (res.start - res.end)); | ||||
|  | ||||
| 	if (ofnode_read_resource_byname(node, "local_response_region", &res)) { | ||||
| 		dev_err(dev, "No reg property for local_response_region\n"); | ||||
| 		return -EINVAL; | ||||
| 	}; | ||||
| 	zynqmp->local_res_regs = devm_ioremap(dev, res.start, | ||||
| 					      (res.start - res.end)); | ||||
|  | ||||
| 	if (ofnode_read_resource_byname(node, "remote_request_region", &res)) { | ||||
| 		dev_err(dev, "No reg property for remote_request_region\n"); | ||||
| 		return -EINVAL; | ||||
| 	}; | ||||
| 	zynqmp->remote_req_regs = devm_ioremap(dev, res.start, | ||||
| 					       (res.start - res.end)); | ||||
|  | ||||
| 	if (ofnode_read_resource_byname(node, "remote_response_region", &res)) { | ||||
| 		dev_err(dev, "No reg property for remote_response_region\n"); | ||||
| 		return -EINVAL; | ||||
| 	}; | ||||
| 	zynqmp->remote_res_regs = devm_ioremap(dev, res.start, | ||||
| 					       (res.start - res.end)); | ||||
|  | ||||
| 	return 0; | ||||
| }; | ||||
|  | ||||
| static const struct udevice_id zynqmp_ipi_ids[] = { | ||||
| 	{ .compatible = "xlnx,zynqmp-ipi-mailbox" }, | ||||
| 	{ } | ||||
| }; | ||||
|  | ||||
| struct mbox_ops zynqmp_ipi_mbox_ops = { | ||||
| 	.send = zynqmp_ipi_send, | ||||
| 	.recv = zynqmp_ipi_recv, | ||||
| }; | ||||
|  | ||||
| U_BOOT_DRIVER(zynqmp_ipi) = { | ||||
| 	.name = "zynqmp-ipi", | ||||
| 	.id = UCLASS_MAILBOX, | ||||
| 	.of_match = zynqmp_ipi_ids, | ||||
| 	.probe = zynqmp_ipi_probe, | ||||
| 	.priv_auto_alloc_size = sizeof(struct zynqmp_ipi), | ||||
| 	.ops = &zynqmp_ipi_mbox_ops, | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user