uboot/drivers/mailbox/zynqmp-ipi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Xilinx Zynq MPSoC Mailbox driver
   4 *
   5 * Copyright (C) 2018-2019 Xilinx, Inc.
   6 */
   7
   8#include <common.h>
   9#include <log.h>
  10#include <asm/io.h>
  11#include <dm.h>
  12#include <mailbox-uclass.h>
  13#include <dm/device_compat.h>
  14#include <mach/sys_proto.h>
  15#include <linux/ioport.h>
  16#include <linux/io.h>
  17#include <wait_bit.h>
  18
  19/* IPI bitmasks, register base */
  20/* TODO: move reg base to DT */
  21#define IPI_BIT_MASK_PMU0     0x10000
  22#define IPI_INT_REG_BASE_APU  0xFF300000
  23
  24struct ipi_int_regs {
  25        u32 trig; /* 0x0  */
  26        u32 obs;  /* 0x4  */
  27        u32 dummy0;
  28        u32 dummy1;
  29        u32 isr;  /* 0x10  */
  30        u32 imr;  /* 0x14  */
  31        u32 ier;  /* 0x18 */
  32        u32 idr;  /* 0x1C */
  33};
  34
  35#define ipi_int_apu ((struct ipi_int_regs *)IPI_INT_REG_BASE_APU)
  36
  37struct zynqmp_ipi {
  38        void __iomem *local_req_regs;
  39        void __iomem *local_res_regs;
  40        void __iomem *remote_req_regs;
  41        void __iomem *remote_res_regs;
  42};
  43
  44static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data)
  45{
  46        const struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data;
  47        struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev);
  48        u32 ret;
  49        u32 *mbx = (u32 *)zynqmp->local_req_regs;
  50
  51        for (size_t i = 0; i < msg->len; i++)
  52                writel(msg->buf[i], &mbx[i]);
  53
  54        /* Write trigger interrupt */
  55        writel(IPI_BIT_MASK_PMU0, &ipi_int_apu->trig);
  56
  57        /* Wait until observation bit is cleared */
  58        ret = wait_for_bit_le32(&ipi_int_apu->obs, IPI_BIT_MASK_PMU0, false,
  59                                1000, false);
  60
  61        debug("%s, send %ld bytes\n", __func__, msg->len);
  62        return ret;
  63};
  64
  65static int zynqmp_ipi_recv(struct mbox_chan *chan, void *data)
  66{
  67        struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data;
  68        struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev);
  69        u32 *mbx = (u32 *)zynqmp->local_res_regs;
  70
  71        /*
  72         * PMU Firmware does not trigger IPI interrupt for API call responses so
  73         * there is no need to check ISR flags
  74         */
  75        for (size_t i = 0; i < msg->len; i++)
  76                msg->buf[i] = readl(&mbx[i]);
  77
  78        debug("%s, recv %ld bytes\n", __func__, msg->len);
  79        return 0;
  80};
  81
  82static int zynqmp_ipi_probe(struct udevice *dev)
  83{
  84        struct zynqmp_ipi *zynqmp = dev_get_priv(dev);
  85        struct resource res;
  86        ofnode node;
  87
  88        debug("%s(dev=%p)\n", __func__, dev);
  89
  90        /* Get subnode where the regs are defined */
  91        /* Note IPI mailbox node needs to be the first one in DT */
  92        node = ofnode_first_subnode(dev_ofnode(dev));
  93
  94        if (ofnode_read_resource_byname(node, "local_request_region", &res)) {
  95                dev_err(dev, "No reg property for local_request_region\n");
  96                return -EINVAL;
  97        };
  98        zynqmp->local_req_regs = devm_ioremap(dev, res.start,
  99                                              (res.start - res.end));
 100
 101        if (ofnode_read_resource_byname(node, "local_response_region", &res)) {
 102                dev_err(dev, "No reg property for local_response_region\n");
 103                return -EINVAL;
 104        };
 105        zynqmp->local_res_regs = devm_ioremap(dev, res.start,
 106                                              (res.start - res.end));
 107
 108        if (ofnode_read_resource_byname(node, "remote_request_region", &res)) {
 109                dev_err(dev, "No reg property for remote_request_region\n");
 110                return -EINVAL;
 111        };
 112        zynqmp->remote_req_regs = devm_ioremap(dev, res.start,
 113                                               (res.start - res.end));
 114
 115        if (ofnode_read_resource_byname(node, "remote_response_region", &res)) {
 116                dev_err(dev, "No reg property for remote_response_region\n");
 117                return -EINVAL;
 118        };
 119        zynqmp->remote_res_regs = devm_ioremap(dev, res.start,
 120                                               (res.start - res.end));
 121
 122        return 0;
 123};
 124
 125static const struct udevice_id zynqmp_ipi_ids[] = {
 126        { .compatible = "xlnx,zynqmp-ipi-mailbox" },
 127        { }
 128};
 129
 130struct mbox_ops zynqmp_ipi_mbox_ops = {
 131        .send = zynqmp_ipi_send,
 132        .recv = zynqmp_ipi_recv,
 133};
 134
 135U_BOOT_DRIVER(zynqmp_ipi) = {
 136        .name = "zynqmp_ipi",
 137        .id = UCLASS_MAILBOX,
 138        .of_match = zynqmp_ipi_ids,
 139        .probe = zynqmp_ipi_probe,
 140        .priv_auto      = sizeof(struct zynqmp_ipi),
 141        .ops = &zynqmp_ipi_mbox_ops,
 142};
 143