1*6238935dSStephen Warren /* 2*6238935dSStephen Warren * Copyright (c) 2016, NVIDIA CORPORATION. 3*6238935dSStephen Warren * 4*6238935dSStephen Warren * SPDX-License-Identifier: GPL-2.0 5*6238935dSStephen Warren */ 6*6238935dSStephen Warren 7*6238935dSStephen Warren #include <common.h> 8*6238935dSStephen Warren #include <dm.h> 9*6238935dSStephen Warren #include <fdtdec.h> 10*6238935dSStephen Warren #include <mailbox_client.h> 11*6238935dSStephen Warren #include <mailbox_uclass.h> 12*6238935dSStephen Warren 13*6238935dSStephen Warren DECLARE_GLOBAL_DATA_PTR; 14*6238935dSStephen Warren 15*6238935dSStephen Warren static inline struct mbox_ops *mbox_dev_ops(struct udevice *dev) 16*6238935dSStephen Warren { 17*6238935dSStephen Warren return (struct mbox_ops *)dev->driver->ops; 18*6238935dSStephen Warren } 19*6238935dSStephen Warren 20*6238935dSStephen Warren static int mbox_of_xlate_default(struct mbox_chan *chan, 21*6238935dSStephen Warren struct fdtdec_phandle_args *args) 22*6238935dSStephen Warren { 23*6238935dSStephen Warren debug("%s(chan=%p)\n", __func__, chan); 24*6238935dSStephen Warren 25*6238935dSStephen Warren if (args->args_count != 1) { 26*6238935dSStephen Warren debug("Invaild args_count: %d\n", args->args_count); 27*6238935dSStephen Warren return -EINVAL; 28*6238935dSStephen Warren } 29*6238935dSStephen Warren 30*6238935dSStephen Warren chan->id = args->args[0]; 31*6238935dSStephen Warren 32*6238935dSStephen Warren return 0; 33*6238935dSStephen Warren } 34*6238935dSStephen Warren 35*6238935dSStephen Warren int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan) 36*6238935dSStephen Warren { 37*6238935dSStephen Warren struct fdtdec_phandle_args args; 38*6238935dSStephen Warren int ret; 39*6238935dSStephen Warren struct udevice *dev_mbox; 40*6238935dSStephen Warren struct mbox_ops *ops; 41*6238935dSStephen Warren 42*6238935dSStephen Warren debug("%s(dev=%p, index=%d, chan=%p)\n", __func__, dev, index, chan); 43*6238935dSStephen Warren 44*6238935dSStephen Warren ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, 45*6238935dSStephen Warren "mboxes", "#mbox-cells", 0, 46*6238935dSStephen Warren index, &args); 47*6238935dSStephen Warren if (ret) { 48*6238935dSStephen Warren debug("%s: fdtdec_parse_phandle_with_args failed: %d\n", 49*6238935dSStephen Warren __func__, ret); 50*6238935dSStephen Warren return ret; 51*6238935dSStephen Warren } 52*6238935dSStephen Warren 53*6238935dSStephen Warren ret = uclass_get_device_by_of_offset(UCLASS_MAILBOX, args.node, 54*6238935dSStephen Warren &dev_mbox); 55*6238935dSStephen Warren if (ret) { 56*6238935dSStephen Warren debug("%s: uclass_get_device_by_of_offset failed: %d\n", 57*6238935dSStephen Warren __func__, ret); 58*6238935dSStephen Warren return ret; 59*6238935dSStephen Warren } 60*6238935dSStephen Warren ops = mbox_dev_ops(dev_mbox); 61*6238935dSStephen Warren 62*6238935dSStephen Warren chan->dev = dev_mbox; 63*6238935dSStephen Warren if (ops->of_xlate) 64*6238935dSStephen Warren ret = ops->of_xlate(chan, &args); 65*6238935dSStephen Warren else 66*6238935dSStephen Warren ret = mbox_of_xlate_default(chan, &args); 67*6238935dSStephen Warren if (ret) { 68*6238935dSStephen Warren debug("of_xlate() failed: %d\n", ret); 69*6238935dSStephen Warren return ret; 70*6238935dSStephen Warren } 71*6238935dSStephen Warren 72*6238935dSStephen Warren ret = ops->request(chan); 73*6238935dSStephen Warren if (ret) { 74*6238935dSStephen Warren debug("ops->request() failed: %d\n", ret); 75*6238935dSStephen Warren return ret; 76*6238935dSStephen Warren } 77*6238935dSStephen Warren 78*6238935dSStephen Warren return 0; 79*6238935dSStephen Warren } 80*6238935dSStephen Warren 81*6238935dSStephen Warren int mbox_get_by_name(struct udevice *dev, const char *name, 82*6238935dSStephen Warren struct mbox_chan *chan) 83*6238935dSStephen Warren { 84*6238935dSStephen Warren int index; 85*6238935dSStephen Warren 86*6238935dSStephen Warren debug("%s(dev=%p, name=%s, chan=%p)\n", __func__, dev, name, chan); 87*6238935dSStephen Warren 88*6238935dSStephen Warren index = fdt_find_string(gd->fdt_blob, dev->of_offset, "mbox-names", 89*6238935dSStephen Warren name); 90*6238935dSStephen Warren if (index < 0) { 91*6238935dSStephen Warren debug("fdt_find_string() failed: %d\n", index); 92*6238935dSStephen Warren return index; 93*6238935dSStephen Warren } 94*6238935dSStephen Warren 95*6238935dSStephen Warren return mbox_get_by_index(dev, index, chan); 96*6238935dSStephen Warren } 97*6238935dSStephen Warren 98*6238935dSStephen Warren int mbox_free(struct mbox_chan *chan) 99*6238935dSStephen Warren { 100*6238935dSStephen Warren struct mbox_ops *ops = mbox_dev_ops(chan->dev); 101*6238935dSStephen Warren 102*6238935dSStephen Warren debug("%s(chan=%p)\n", __func__, chan); 103*6238935dSStephen Warren 104*6238935dSStephen Warren return ops->free(chan); 105*6238935dSStephen Warren } 106*6238935dSStephen Warren 107*6238935dSStephen Warren int mbox_send(struct mbox_chan *chan, const void *data) 108*6238935dSStephen Warren { 109*6238935dSStephen Warren struct mbox_ops *ops = mbox_dev_ops(chan->dev); 110*6238935dSStephen Warren 111*6238935dSStephen Warren debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 112*6238935dSStephen Warren 113*6238935dSStephen Warren return ops->send(chan, data); 114*6238935dSStephen Warren } 115*6238935dSStephen Warren 116*6238935dSStephen Warren int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us) 117*6238935dSStephen Warren { 118*6238935dSStephen Warren struct mbox_ops *ops = mbox_dev_ops(chan->dev); 119*6238935dSStephen Warren ulong start_time; 120*6238935dSStephen Warren int ret; 121*6238935dSStephen Warren 122*6238935dSStephen Warren debug("%s(chan=%p, data=%p, timeout_us=%ld)\n", __func__, chan, data, 123*6238935dSStephen Warren timeout_us); 124*6238935dSStephen Warren 125*6238935dSStephen Warren start_time = timer_get_us(); 126*6238935dSStephen Warren /* 127*6238935dSStephen Warren * Account for partial us ticks, but if timeout_us is 0, ensure we 128*6238935dSStephen Warren * still don't wait at all. 129*6238935dSStephen Warren */ 130*6238935dSStephen Warren if (timeout_us) 131*6238935dSStephen Warren timeout_us++; 132*6238935dSStephen Warren 133*6238935dSStephen Warren for (;;) { 134*6238935dSStephen Warren ret = ops->recv(chan, data); 135*6238935dSStephen Warren if (ret != -ENODATA) 136*6238935dSStephen Warren return ret; 137*6238935dSStephen Warren if ((timer_get_us() - start_time) >= timeout_us) 138*6238935dSStephen Warren return -ETIMEDOUT; 139*6238935dSStephen Warren } 140*6238935dSStephen Warren } 141*6238935dSStephen Warren 142*6238935dSStephen Warren UCLASS_DRIVER(mailbox) = { 143*6238935dSStephen Warren .id = UCLASS_MAILBOX, 144*6238935dSStephen Warren .name = "mailbox", 145*6238935dSStephen Warren }; 146