Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/firmware/arm/scmi.c
| /*- | /*- | ||||
| * SPDX-License-Identifier: BSD-2-Clause | * SPDX-License-Identifier: BSD-2-Clause | ||||
| * | * | ||||
| * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com> | * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com> | ||||
| * Copyright (c) 2023 Arm Ltd | |||||
| * | * | ||||
| * This work was supported by Innovate UK project 105694, "Digital Security | * This work was supported by Innovate UK project 105694, "Digital Security | ||||
| * by Design (DSbD) Technology Platform Prototype". | * by Design (DSbD) Technology Platform Prototype". | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
| * modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
| * are met: | * are met: | ||||
| * 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
| Show All 28 Lines | |||||
| #include <dev/fdt/simplebus.h> | #include <dev/fdt/simplebus.h> | ||||
| #include <dev/fdt/fdt_common.h> | #include <dev/fdt/fdt_common.h> | ||||
| #include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
| #include "dev/mailbox/arm/arm_doorbell.h" | #include "dev/mailbox/arm/arm_doorbell.h" | ||||
| #include "scmi.h" | #include "scmi.h" | ||||
| #include "scmi_protocols.h" | #include "scmi_protocols.h" | ||||
| #include "scmi_shmem.h" | |||||
| static device_t | #define SCMI_HDR_TOKEN_S 18 | ||||
| scmi_get_shmem(struct scmi_softc *sc, int index) | #define SCMI_HDR_TOKEN_BF (0x3fff) | ||||
| { | #define SCMI_HDR_TOKEN_M (SCMI_HDR_TOKEN_BF << SCMI_HDR_TOKEN_S) | ||||
| phandle_t *shmems; | |||||
| phandle_t node; | |||||
| device_t dev; | |||||
| size_t len; | |||||
| node = ofw_bus_get_node(sc->dev); | #define SCMI_HDR_PROTOCOL_ID_S 10 | ||||
| if (node <= 0) | #define SCMI_HDR_PROTOCOL_ID_BF (0xff) | ||||
| return (NULL); | #define SCMI_HDR_PROTOCOL_ID_M \ | ||||
| (SCMI_HDR_PROTOCOL_ID_BF << SCMI_HDR_PROTOCOL_ID_S) | |||||
| len = OF_getencprop_alloc_multi(node, "shmem", sizeof(*shmems), | #define SCMI_HDR_MESSAGE_TYPE_S 8 | ||||
| (void **)&shmems); | #define SCMI_HDR_MESSAGE_TYPE_BF (0x3) | ||||
| if (len <= 0) { | #define SCMI_HDR_MESSAGE_TYPE_M \ | ||||
| device_printf(sc->dev, "%s: Can't get shmem node.\n", __func__); | (SCMI_HDR_MESSAGE_TYPE_BF << SCMI_HDR_MESSAGE_TYPE_S) | ||||
| return (NULL); | |||||
| } | |||||
| if (index >= len) { | #define SCMI_HDR_MESSAGE_ID_S 0 | ||||
| OF_prop_free(shmems); | #define SCMI_HDR_MESSAGE_ID_BF (0xff) | ||||
| return (NULL); | #define SCMI_HDR_MESSAGE_ID_M \ | ||||
| } | (SCMI_HDR_MESSAGE_ID_BF << SCMI_HDR_MESSAGE_ID_S) | ||||
| dev = OF_device_from_xref(shmems[index]); | #define SCMI_MSG_TYPE_CMD 0 | ||||
| if (dev == NULL) | #define SCMI_MSG_TYPE_DRESP 2 | ||||
| device_printf(sc->dev, "%s: Can't get shmem device.\n", | #define SCMI_MSG_TYPE_NOTIF 3 | ||||
| __func__); | |||||
| OF_prop_free(shmems); | |||||
| return (dev); | |||||
| } | |||||
| static int | static int | ||||
| scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req) | scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req) | ||||
| { | { | ||||
| struct scmi_smt_header hdr; | uint32_t reply_header; | ||||
| int ret; | int ret; | ||||
| bzero(&hdr, sizeof(struct scmi_smt_header)); | |||||
| SCMI_ASSERT_LOCKED(sc); | SCMI_ASSERT_LOCKED(sc); | ||||
| /* Read header */ | req->msg_header = req->message_id << SCMI_HDR_MESSAGE_ID_S; | ||||
| scmi_shmem_read(sc->tx_shmem, 0, &hdr, SMT_HEADER_SIZE); | |||||
| if ((hdr.channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) == 0) | |||||
| return (1); | |||||
| /* Update header */ | |||||
| hdr.channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE; | |||||
| hdr.msg_header = req->protocol_id << SMT_HEADER_PROTOCOL_ID_S; | |||||
| hdr.msg_header |= req->message_id << SMT_HEADER_MESSAGE_ID_S; | |||||
| /* TODO: Allocate a token */ | /* TODO: Allocate a token */ | ||||
| hdr.length = sizeof(hdr.msg_header) + req->in_size; | req->msg_header |= SCMI_MSG_TYPE_CMD << SCMI_HDR_MESSAGE_TYPE_S; | ||||
| hdr.flags |= SCMI_SHMEM_FLAG_INTR_ENABLED; | req->msg_header |= req->protocol_id << SCMI_HDR_PROTOCOL_ID_S; | ||||
| /* Write header */ | ret = scmi_shmem_prepare_msg(sc->a2p_dev, req); | ||||
| scmi_shmem_write(sc->tx_shmem, 0, &hdr, SMT_HEADER_SIZE); | if (ret != 0) | ||||
| return (ret); | |||||
| /* Write request */ | |||||
| scmi_shmem_write(sc->tx_shmem, SMT_HEADER_SIZE, req->in_buf, | |||||
| req->in_size); | |||||
| ret = SCMI_XFER_MSG(sc->dev); | ret = SCMI_XFER_MSG(sc->dev); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| return (ret); | return (ret); | ||||
| /* Read header. */ | /* Read header. */ | ||||
| scmi_shmem_read(sc->tx_shmem, 0, &hdr, SMT_HEADER_SIZE); | ret = scmi_shmem_read_msg_header(sc->a2p_dev, &reply_header); | ||||
| if (ret != 0) | |||||
| return (ret); | |||||
| /* Read response */ | if (reply_header != req->msg_header) | ||||
| scmi_shmem_read(sc->tx_shmem, SMT_HEADER_SIZE, req->out_buf, | return (EPROTO); | ||||
| req->out_size); | |||||
| return (0); | return (scmi_shmem_read_msg_payload(sc->a2p_dev, req->out_buf, | ||||
| req->out_size)); | |||||
| } | } | ||||
| int | int | ||||
| scmi_request(device_t dev, struct scmi_req *req) | scmi_request(device_t dev, struct scmi_req *req) | ||||
| { | { | ||||
| struct scmi_softc *sc; | struct scmi_softc *sc; | ||||
| int error; | int error; | ||||
| Show All 15 Lines | scmi_attach(device_t dev) | ||||
| sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
| sc->dev = dev; | sc->dev = dev; | ||||
| node = ofw_bus_get_node(dev); | node = ofw_bus_get_node(dev); | ||||
| if (node == -1) | if (node == -1) | ||||
| return (ENXIO); | return (ENXIO); | ||||
| sc->tx_shmem = scmi_get_shmem(sc, 0); | sc->a2p_dev = scmi_shmem_get(dev, node, SCMI_CHAN_A2P); | ||||
| if (sc->tx_shmem == NULL) { | if (sc->a2p_dev == NULL) { | ||||
| device_printf(dev, "TX shmem dev not found.\n"); | device_printf(dev, "A2P shmem dev not found.\n"); | ||||
| return (ENXIO); | return (ENXIO); | ||||
| } | } | ||||
| mtx_init(&sc->mtx, device_get_nameunit(dev), "SCMI", MTX_DEF); | mtx_init(&sc->mtx, device_get_nameunit(dev), "SCMI", MTX_DEF); | ||||
| simplebus_init(dev, node); | simplebus_init(dev, node); | ||||
| /* | /* | ||||
| Show All 34 Lines | |||||