154b96380SRuslan Bukin /*- 254b96380SRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause 354b96380SRuslan Bukin * 454b96380SRuslan Bukin * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com> 5d220b1cfSCristian Marussi * Copyright (c) 2023 Arm Ltd 654b96380SRuslan Bukin * 754b96380SRuslan Bukin * This work was supported by Innovate UK project 105694, "Digital Security 854b96380SRuslan Bukin * by Design (DSbD) Technology Platform Prototype". 954b96380SRuslan Bukin * 1054b96380SRuslan Bukin * Redistribution and use in source and binary forms, with or without 1154b96380SRuslan Bukin * modification, are permitted provided that the following conditions 1254b96380SRuslan Bukin * are met: 1354b96380SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 1454b96380SRuslan Bukin * notice, this list of conditions and the following disclaimer. 1554b96380SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 1654b96380SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 1754b96380SRuslan Bukin * documentation and/or other materials provided with the distribution. 1854b96380SRuslan Bukin * 1954b96380SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2054b96380SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2154b96380SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2254b96380SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2354b96380SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2454b96380SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2554b96380SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2654b96380SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2754b96380SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2854b96380SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2954b96380SRuslan Bukin * SUCH DAMAGE. 3054b96380SRuslan Bukin */ 3154b96380SRuslan Bukin 3254b96380SRuslan Bukin #include <sys/param.h> 3354b96380SRuslan Bukin #include <sys/systm.h> 3454b96380SRuslan Bukin #include <sys/bus.h> 3554b96380SRuslan Bukin #include <sys/cpu.h> 3654b96380SRuslan Bukin #include <sys/kernel.h> 3754b96380SRuslan Bukin #include <sys/lock.h> 3854b96380SRuslan Bukin #include <sys/module.h> 3954b96380SRuslan Bukin #include <sys/mutex.h> 4054b96380SRuslan Bukin 41be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 4254b96380SRuslan Bukin #include <dev/fdt/simplebus.h> 4354b96380SRuslan Bukin #include <dev/fdt/fdt_common.h> 4454b96380SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 4554b96380SRuslan Bukin 4654b96380SRuslan Bukin #include "dev/mailbox/arm/arm_doorbell.h" 4754b96380SRuslan Bukin 4854b96380SRuslan Bukin #include "scmi.h" 4954b96380SRuslan Bukin #include "scmi_protocols.h" 50d220b1cfSCristian Marussi #include "scmi_shmem.h" 5154b96380SRuslan Bukin 52d220b1cfSCristian Marussi #define SCMI_HDR_TOKEN_S 18 53d220b1cfSCristian Marussi #define SCMI_HDR_TOKEN_BF (0x3fff) 54d220b1cfSCristian Marussi #define SCMI_HDR_TOKEN_M (SCMI_HDR_TOKEN_BF << SCMI_HDR_TOKEN_S) 5554b96380SRuslan Bukin 56d220b1cfSCristian Marussi #define SCMI_HDR_PROTOCOL_ID_S 10 57d220b1cfSCristian Marussi #define SCMI_HDR_PROTOCOL_ID_BF (0xff) 58d220b1cfSCristian Marussi #define SCMI_HDR_PROTOCOL_ID_M \ 59d220b1cfSCristian Marussi (SCMI_HDR_PROTOCOL_ID_BF << SCMI_HDR_PROTOCOL_ID_S) 6054b96380SRuslan Bukin 61d220b1cfSCristian Marussi #define SCMI_HDR_MESSAGE_TYPE_S 8 62d220b1cfSCristian Marussi #define SCMI_HDR_MESSAGE_TYPE_BF (0x3) 63d220b1cfSCristian Marussi #define SCMI_HDR_MESSAGE_TYPE_M \ 64d220b1cfSCristian Marussi (SCMI_HDR_MESSAGE_TYPE_BF << SCMI_HDR_MESSAGE_TYPE_S) 6554b96380SRuslan Bukin 66d220b1cfSCristian Marussi #define SCMI_HDR_MESSAGE_ID_S 0 67d220b1cfSCristian Marussi #define SCMI_HDR_MESSAGE_ID_BF (0xff) 68d220b1cfSCristian Marussi #define SCMI_HDR_MESSAGE_ID_M \ 69d220b1cfSCristian Marussi (SCMI_HDR_MESSAGE_ID_BF << SCMI_HDR_MESSAGE_ID_S) 7054b96380SRuslan Bukin 71d220b1cfSCristian Marussi #define SCMI_MSG_TYPE_CMD 0 72d220b1cfSCristian Marussi #define SCMI_MSG_TYPE_DRESP 2 73d220b1cfSCristian Marussi #define SCMI_MSG_TYPE_NOTIF 3 7454b96380SRuslan Bukin 7554b96380SRuslan Bukin static int 7654b96380SRuslan Bukin scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req) 7754b96380SRuslan Bukin { 78d220b1cfSCristian Marussi uint32_t reply_header; 79d46f01fdSAndrew Turner int ret; 8054b96380SRuslan Bukin 8154b96380SRuslan Bukin SCMI_ASSERT_LOCKED(sc); 8254b96380SRuslan Bukin 83d220b1cfSCristian Marussi req->msg_header = req->message_id << SCMI_HDR_MESSAGE_ID_S; 84d46f01fdSAndrew Turner /* TODO: Allocate a token */ 85d220b1cfSCristian Marussi req->msg_header |= SCMI_MSG_TYPE_CMD << SCMI_HDR_MESSAGE_TYPE_S; 86d220b1cfSCristian Marussi req->msg_header |= req->protocol_id << SCMI_HDR_PROTOCOL_ID_S; 8754b96380SRuslan Bukin 88cbcfdff0SCristian Marussi ret = scmi_shmem_prepare_msg(sc->a2p_dev, req, cold); 89d220b1cfSCristian Marussi if (ret != 0) 90d220b1cfSCristian Marussi return (ret); 9154b96380SRuslan Bukin 92d46f01fdSAndrew Turner ret = SCMI_XFER_MSG(sc->dev); 93d46f01fdSAndrew Turner if (ret != 0) 94a0ba2a97SCristian Marussi goto out; 9554b96380SRuslan Bukin 9654b96380SRuslan Bukin /* Read header. */ 97d220b1cfSCristian Marussi ret = scmi_shmem_read_msg_header(sc->a2p_dev, &reply_header); 98d220b1cfSCristian Marussi if (ret != 0) 99a0ba2a97SCristian Marussi goto out; 100a0ba2a97SCristian Marussi 101a0ba2a97SCristian Marussi if (reply_header != req->msg_header) { 102a0ba2a97SCristian Marussi ret = EPROTO; 103a0ba2a97SCristian Marussi goto out; 104a0ba2a97SCristian Marussi } 105a0ba2a97SCristian Marussi 106a0ba2a97SCristian Marussi ret = scmi_shmem_read_msg_payload(sc->a2p_dev, req->out_buf, 107a0ba2a97SCristian Marussi req->out_size); 108a0ba2a97SCristian Marussi 109a0ba2a97SCristian Marussi out: 110a0ba2a97SCristian Marussi scmi_shmem_tx_complete(sc->a2p_dev); 111a0ba2a97SCristian Marussi 112d220b1cfSCristian Marussi return (ret); 11354b96380SRuslan Bukin } 11454b96380SRuslan Bukin 11554b96380SRuslan Bukin int 11654b96380SRuslan Bukin scmi_request(device_t dev, struct scmi_req *req) 11754b96380SRuslan Bukin { 11854b96380SRuslan Bukin struct scmi_softc *sc; 11954b96380SRuslan Bukin int error; 12054b96380SRuslan Bukin 12154b96380SRuslan Bukin sc = device_get_softc(dev); 12254b96380SRuslan Bukin 12354b96380SRuslan Bukin SCMI_LOCK(sc); 12454b96380SRuslan Bukin error = scmi_request_locked(sc, req); 12554b96380SRuslan Bukin SCMI_UNLOCK(sc); 12654b96380SRuslan Bukin 12754b96380SRuslan Bukin return (error); 12854b96380SRuslan Bukin } 12954b96380SRuslan Bukin 130d46f01fdSAndrew Turner int 13154b96380SRuslan Bukin scmi_attach(device_t dev) 13254b96380SRuslan Bukin { 13354b96380SRuslan Bukin struct scmi_softc *sc; 13454b96380SRuslan Bukin phandle_t node; 13554b96380SRuslan Bukin int error; 13654b96380SRuslan Bukin 13754b96380SRuslan Bukin sc = device_get_softc(dev); 13854b96380SRuslan Bukin sc->dev = dev; 13954b96380SRuslan Bukin 14054b96380SRuslan Bukin node = ofw_bus_get_node(dev); 14154b96380SRuslan Bukin if (node == -1) 14254b96380SRuslan Bukin return (ENXIO); 14354b96380SRuslan Bukin 144d220b1cfSCristian Marussi sc->a2p_dev = scmi_shmem_get(dev, node, SCMI_CHAN_A2P); 145d220b1cfSCristian Marussi if (sc->a2p_dev == NULL) { 146d220b1cfSCristian Marussi device_printf(dev, "A2P shmem dev not found.\n"); 14754b96380SRuslan Bukin return (ENXIO); 14854b96380SRuslan Bukin } 14954b96380SRuslan Bukin 15054b96380SRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(dev), "SCMI", MTX_DEF); 15154b96380SRuslan Bukin 15254b96380SRuslan Bukin simplebus_init(dev, node); 15354b96380SRuslan Bukin 15454b96380SRuslan Bukin /* 15554b96380SRuslan Bukin * Allow devices to identify. 15654b96380SRuslan Bukin */ 15754b96380SRuslan Bukin bus_generic_probe(dev); 15854b96380SRuslan Bukin 15954b96380SRuslan Bukin /* 16054b96380SRuslan Bukin * Now walk the OFW tree and attach top-level devices. 16154b96380SRuslan Bukin */ 16254b96380SRuslan Bukin for (node = OF_child(node); node > 0; node = OF_peer(node)) 16354b96380SRuslan Bukin simplebus_add_device(dev, node, 0, NULL, -1, NULL); 16454b96380SRuslan Bukin 16554b96380SRuslan Bukin error = bus_generic_attach(dev); 16654b96380SRuslan Bukin 16754b96380SRuslan Bukin return (error); 16854b96380SRuslan Bukin } 16954b96380SRuslan Bukin 17054b96380SRuslan Bukin static int 17154b96380SRuslan Bukin scmi_detach(device_t dev) 17254b96380SRuslan Bukin { 17354b96380SRuslan Bukin 17454b96380SRuslan Bukin return (0); 17554b96380SRuslan Bukin } 17654b96380SRuslan Bukin 17754b96380SRuslan Bukin static device_method_t scmi_methods[] = { 17854b96380SRuslan Bukin DEVMETHOD(device_attach, scmi_attach), 17954b96380SRuslan Bukin DEVMETHOD(device_detach, scmi_detach), 180d46f01fdSAndrew Turner 18154b96380SRuslan Bukin DEVMETHOD_END 18254b96380SRuslan Bukin }; 18354b96380SRuslan Bukin 18454b96380SRuslan Bukin DEFINE_CLASS_1(scmi, scmi_driver, scmi_methods, sizeof(struct scmi_softc), 18554b96380SRuslan Bukin simplebus_driver); 18654b96380SRuslan Bukin 18754b96380SRuslan Bukin DRIVER_MODULE(scmi, simplebus, scmi_driver, 0, 0); 18854b96380SRuslan Bukin MODULE_VERSION(scmi, 1); 189