^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk/tegra.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/genalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/mailbox_client.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/semaphore.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/sched/clock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <soc/tegra/bpmp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <soc/tegra/bpmp-abi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <soc/tegra/ivc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "bpmp-private.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define MSG_ACK BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MSG_RING BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define TAG_SZ 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static inline struct tegra_bpmp *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) mbox_client_to_bpmp(struct mbox_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return container_of(client, struct tegra_bpmp, mbox.client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static inline const struct tegra_bpmp_ops *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) channel_to_ops(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct tegra_bpmp *bpmp = channel->bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return bpmp->soc->ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct tegra_bpmp *tegra_bpmp_get(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct tegra_bpmp *bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) pdev = of_find_device_by_node(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!pdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) bpmp = ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) goto put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) bpmp = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (!bpmp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) bpmp = ERR_PTR(-EPROBE_DEFER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) put_device(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) goto put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) EXPORT_SYMBOL_GPL(tegra_bpmp_get);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) void tegra_bpmp_put(struct tegra_bpmp *bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) put_device(bpmp->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) EXPORT_SYMBOL_GPL(tegra_bpmp_put);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) tegra_bpmp_channel_get_thread_index(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct tegra_bpmp *bpmp = channel->bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) count = bpmp->soc->channels.thread.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) index = channel - channel->bpmp->threaded_channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (index < 0 || index >= count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static bool tegra_bpmp_message_valid(const struct tegra_bpmp_message *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return (msg->tx.size <= MSG_DATA_MIN_SZ) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) (msg->rx.size <= MSG_DATA_MIN_SZ) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) (msg->tx.size == 0 || msg->tx.data) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) (msg->rx.size == 0 || msg->rx.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static bool tegra_bpmp_is_response_ready(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return ops->is_response_ready(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static bool tegra_bpmp_is_request_ready(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return ops->is_request_ready(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static int tegra_bpmp_wait_response(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ktime_t end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) end = ktime_add_us(ktime_get(), timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (tegra_bpmp_is_response_ready(channel))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) } while (ktime_before(ktime_get(), end));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static int tegra_bpmp_ack_response(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return ops->ack_response(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int tegra_bpmp_ack_request(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return ops->ack_request(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static bool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) tegra_bpmp_is_request_channel_free(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return ops->is_request_channel_free(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static bool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) tegra_bpmp_is_response_channel_free(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return ops->is_response_channel_free(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) tegra_bpmp_wait_request_channel_free(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) ktime_t start, now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) start = ns_to_ktime(local_clock());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (tegra_bpmp_is_request_channel_free(channel))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) now = ns_to_ktime(local_clock());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) } while (ktime_us_delta(now, start) < timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static int tegra_bpmp_post_request(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return ops->post_request(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static int tegra_bpmp_post_response(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) const struct tegra_bpmp_ops *ops = channel_to_ops(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return ops->post_response(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static int tegra_bpmp_ring_doorbell(struct tegra_bpmp *bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return bpmp->soc->ops->ring_doorbell(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) void *data, size_t size, int *ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (data && size > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) memcpy(data, channel->ib->data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) err = tegra_bpmp_ack_response(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) *ret = channel->ib->code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) void *data, size_t size, int *ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct tegra_bpmp *bpmp = channel->bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ssize_t err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) index = tegra_bpmp_channel_get_thread_index(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (index < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) err = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) spin_lock_irqsave(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) err = __tegra_bpmp_channel_read(channel, data, size, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) clear_bit(index, bpmp->threaded.allocated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) spin_unlock_irqrestore(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) up(&bpmp->threaded.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) unsigned int mrq, unsigned long flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) const void *data, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) channel->ob->code = mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) channel->ob->flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (data && size > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) memcpy(channel->ob->data, data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return tegra_bpmp_post_request(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static struct tegra_bpmp_channel *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) const void *data, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) unsigned long timeout = bpmp->soc->channels.thread.timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) unsigned int count = bpmp->soc->channels.thread.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct tegra_bpmp_channel *channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) err = down_timeout(&bpmp->threaded.lock, usecs_to_jiffies(timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) spin_lock_irqsave(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) index = find_first_zero_bit(bpmp->threaded.allocated, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (index == count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) channel = &bpmp->threaded_channels[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (!tegra_bpmp_is_request_channel_free(channel)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) set_bit(index, bpmp->threaded.allocated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) err = __tegra_bpmp_channel_write(channel, mrq, MSG_ACK | MSG_RING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) goto clear_allocated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) set_bit(index, bpmp->threaded.busy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) spin_unlock_irqrestore(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) clear_allocated:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) clear_bit(index, bpmp->threaded.allocated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) spin_unlock_irqrestore(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) up(&bpmp->threaded.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) unsigned int mrq, unsigned long flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) const void *data, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) err = tegra_bpmp_wait_request_channel_free(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return __tegra_bpmp_channel_write(channel, mrq, flags, data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct tegra_bpmp_message *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) struct tegra_bpmp_channel *channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (WARN_ON(!irqs_disabled()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if (!tegra_bpmp_message_valid(msg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) channel = bpmp->tx_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) spin_lock(&bpmp->atomic_tx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) err = tegra_bpmp_channel_write(channel, msg->mrq, MSG_ACK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) msg->tx.data, msg->tx.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) spin_unlock(&bpmp->atomic_tx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) spin_unlock(&bpmp->atomic_tx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) err = tegra_bpmp_ring_doorbell(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) err = tegra_bpmp_wait_response(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return __tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) &msg->rx.ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) EXPORT_SYMBOL_GPL(tegra_bpmp_transfer_atomic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) int tegra_bpmp_transfer(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) struct tegra_bpmp_message *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) struct tegra_bpmp_channel *channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (WARN_ON(irqs_disabled()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (!tegra_bpmp_message_valid(msg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) msg->tx.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (IS_ERR(channel))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) return PTR_ERR(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) err = tegra_bpmp_ring_doorbell(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) timeout = usecs_to_jiffies(bpmp->soc->channels.thread.timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) err = wait_for_completion_timeout(&channel->completion, timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (err == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) &msg->rx.ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) EXPORT_SYMBOL_GPL(tegra_bpmp_transfer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) unsigned int mrq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) struct tegra_bpmp_mrq *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) list_for_each_entry(entry, &bpmp->mrqs, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (entry->mrq == mrq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) return entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) const void *data, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) unsigned long flags = channel->ib->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct tegra_bpmp *bpmp = channel->bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (WARN_ON(size > MSG_DATA_MIN_SZ))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) err = tegra_bpmp_ack_request(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (WARN_ON(err < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if ((flags & MSG_ACK) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (WARN_ON(!tegra_bpmp_is_response_channel_free(channel)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) channel->ob->code = code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (data && size > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) memcpy(channel->ob->data, data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) err = tegra_bpmp_post_response(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (WARN_ON(err < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (flags & MSG_RING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) err = tegra_bpmp_ring_doorbell(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (WARN_ON(err < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_return);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) unsigned int mrq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) struct tegra_bpmp_mrq *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) u32 zero = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) spin_lock(&bpmp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) entry = tegra_bpmp_find_mrq(bpmp, mrq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (!entry) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) spin_unlock(&bpmp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) tegra_bpmp_mrq_return(channel, -EINVAL, &zero, sizeof(zero));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) entry->handler(mrq, channel, entry->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) spin_unlock(&bpmp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) tegra_bpmp_mrq_handler_t handler, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) struct tegra_bpmp_mrq *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (!handler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) entry = devm_kzalloc(bpmp->dev, sizeof(*entry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) spin_lock_irqsave(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) entry->mrq = mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) entry->handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) entry->data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) list_add(&entry->list, &bpmp->mrqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) spin_unlock_irqrestore(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) EXPORT_SYMBOL_GPL(tegra_bpmp_request_mrq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct tegra_bpmp_mrq *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) spin_lock_irqsave(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) entry = tegra_bpmp_find_mrq(bpmp, mrq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) list_del(&entry->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) devm_kfree(bpmp->dev, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) spin_unlock_irqrestore(&bpmp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) struct mrq_query_abi_response resp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) struct tegra_bpmp_message msg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) .mrq = MRQ_QUERY_ABI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) .tx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) .data = &req,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) .size = sizeof(req),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) .rx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) .data = &resp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) .size = sizeof(resp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) err = tegra_bpmp_transfer(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (err || msg.rx.ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return resp.status == 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_is_supported);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) struct tegra_bpmp_channel *channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) struct mrq_ping_request *request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) struct mrq_ping_response response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) request = (struct mrq_ping_request *)channel->ib->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) memset(&response, 0, sizeof(response));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) response.reply = request->challenge << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) static int tegra_bpmp_ping(struct tegra_bpmp *bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) struct mrq_ping_response response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) struct mrq_ping_request request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) struct tegra_bpmp_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) ktime_t start, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) memset(&request, 0, sizeof(request));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) request.challenge = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) memset(&response, 0, sizeof(response));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) memset(&msg, 0, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) msg.mrq = MRQ_PING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) msg.tx.data = &request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) msg.tx.size = sizeof(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) msg.rx.data = &response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) msg.rx.size = sizeof(response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) start = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) err = tegra_bpmp_transfer_atomic(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) end = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) dev_dbg(bpmp->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) "ping ok: challenge: %u, response: %u, time: %lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) request.challenge, response.reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) ktime_to_us(ktime_sub(end, start)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /* deprecated version of tag query */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static int tegra_bpmp_get_firmware_tag_old(struct tegra_bpmp *bpmp, char *tag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct mrq_query_tag_request request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) struct tegra_bpmp_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) dma_addr_t phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) void *virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (size != TAG_SZ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) virt = dma_alloc_coherent(bpmp->dev, TAG_SZ, &phys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) GFP_KERNEL | GFP_DMA32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (!virt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) memset(&request, 0, sizeof(request));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) request.addr = phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) memset(&msg, 0, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) msg.mrq = MRQ_QUERY_TAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) msg.tx.data = &request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) msg.tx.size = sizeof(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) err = tegra_bpmp_transfer_atomic(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (err == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) memcpy(tag, virt, TAG_SZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) dma_free_coherent(bpmp->dev, TAG_SZ, virt, phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (tegra_bpmp_mrq_is_supported(bpmp, MRQ_QUERY_FW_TAG)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) struct mrq_query_fw_tag_response resp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) struct tegra_bpmp_message msg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) .mrq = MRQ_QUERY_FW_TAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) .rx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) .data = &resp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) .size = sizeof(resp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (size != sizeof(resp.tag))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) err = tegra_bpmp_transfer(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) if (msg.rx.ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) memcpy(tag, resp.tag, sizeof(resp.tag));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return tegra_bpmp_get_firmware_tag_old(bpmp, tag, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) unsigned long flags = channel->ob->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if ((flags & MSG_RING) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) complete(&channel->completion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) void tegra_bpmp_handle_rx(struct tegra_bpmp *bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) struct tegra_bpmp_channel *channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) unsigned int i, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) unsigned long *busy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) channel = bpmp->rx_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) count = bpmp->soc->channels.thread.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) busy = bpmp->threaded.busy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) if (tegra_bpmp_is_request_ready(channel))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) spin_lock(&bpmp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) for_each_set_bit(i, busy, count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) struct tegra_bpmp_channel *channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) channel = &bpmp->threaded_channels[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) if (tegra_bpmp_is_response_ready(channel)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) tegra_bpmp_channel_signal(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) clear_bit(i, busy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) spin_unlock(&bpmp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) static int tegra_bpmp_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) struct tegra_bpmp *bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) char tag[TAG_SZ];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) size_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) bpmp = devm_kzalloc(&pdev->dev, sizeof(*bpmp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (!bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) bpmp->soc = of_device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) bpmp->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) INIT_LIST_HEAD(&bpmp->mrqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) spin_lock_init(&bpmp->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) bpmp->threaded.count = bpmp->soc->channels.thread.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) sema_init(&bpmp->threaded.lock, bpmp->threaded.count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) size = BITS_TO_LONGS(bpmp->threaded.count) * sizeof(long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) bpmp->threaded.allocated = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (!bpmp->threaded.allocated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) bpmp->threaded.busy = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) if (!bpmp->threaded.busy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) spin_lock_init(&bpmp->atomic_tx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) bpmp->tx_channel = devm_kzalloc(&pdev->dev, sizeof(*bpmp->tx_channel),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) if (!bpmp->tx_channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) bpmp->rx_channel = devm_kzalloc(&pdev->dev, sizeof(*bpmp->rx_channel),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (!bpmp->rx_channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) bpmp->threaded_channels = devm_kcalloc(&pdev->dev, bpmp->threaded.count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) sizeof(*bpmp->threaded_channels),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (!bpmp->threaded_channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) err = bpmp->soc->ops->init(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) err = tegra_bpmp_request_mrq(bpmp, MRQ_PING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) tegra_bpmp_mrq_handle_ping, bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) goto deinit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) err = tegra_bpmp_ping(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) dev_err(&pdev->dev, "failed to ping BPMP: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) goto free_mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) goto free_mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) dev_info(&pdev->dev, "firmware: %.*s\n", (int)sizeof(tag), tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) platform_set_drvdata(pdev, bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) err = of_platform_default_populate(pdev->dev.of_node, NULL, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) goto free_mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (of_find_property(pdev->dev.of_node, "#clock-cells", NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) err = tegra_bpmp_init_clocks(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) goto free_mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) err = tegra_bpmp_init_resets(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) goto free_mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) if (of_find_property(pdev->dev.of_node, "#power-domain-cells", NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) err = tegra_bpmp_init_powergates(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) goto free_mrq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) err = tegra_bpmp_init_debugfs(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) dev_err(&pdev->dev, "debugfs initialization failed: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) free_mrq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) tegra_bpmp_free_mrq(bpmp, MRQ_PING, bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) deinit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (bpmp->soc->ops->deinit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) bpmp->soc->ops->deinit(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) static int __maybe_unused tegra_bpmp_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) struct tegra_bpmp *bpmp = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (bpmp->soc->ops->resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) return bpmp->soc->ops->resume(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) static const struct dev_pm_ops tegra_bpmp_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) .resume_noirq = tegra_bpmp_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) static const struct tegra_bpmp_soc tegra186_soc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) .channels = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) .cpu_tx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) .offset = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) .timeout = 60 * USEC_PER_SEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) .thread = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) .offset = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) .count = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) .timeout = 600 * USEC_PER_SEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) .cpu_rx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) .offset = 13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) .timeout = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) .ops = &tegra186_bpmp_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) .num_resets = 193,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) static const struct tegra_bpmp_soc tegra210_soc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) .channels = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) .cpu_tx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) .offset = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) .count = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) .timeout = 60 * USEC_PER_SEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) .thread = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) .offset = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) .count = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) .timeout = 600 * USEC_PER_SEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) .cpu_rx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) .offset = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) .count = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) .timeout = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) .ops = &tegra210_bpmp_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) static const struct of_device_id tegra_bpmp_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) { .compatible = "nvidia,tegra210-bpmp", .data = &tegra210_soc },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) static struct platform_driver tegra_bpmp_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) .name = "tegra-bpmp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) .of_match_table = tegra_bpmp_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) .pm = &tegra_bpmp_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) .suppress_bind_attrs = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) .probe = tegra_bpmp_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) builtin_platform_driver(tegra_bpmp_driver);