16b291e80STanmay Shah // SPDX-License-Identifier: GPL-2.0 26b291e80STanmay Shah /* 36b291e80STanmay Shah * ZynqMP R5 Remote Processor driver 46b291e80STanmay Shah * 56b291e80STanmay Shah */ 66b291e80STanmay Shah 76b291e80STanmay Shah #include <dt-bindings/power/xlnx-zynqmp-power.h> 86b291e80STanmay Shah #include <linux/dma-mapping.h> 96b291e80STanmay Shah #include <linux/firmware/xlnx-zynqmp.h> 106b291e80STanmay Shah #include <linux/kernel.h> 115dfb28c2STanmay Shah #include <linux/mailbox_client.h> 125dfb28c2STanmay Shah #include <linux/mailbox/zynqmp-ipi-message.h> 136b291e80STanmay Shah #include <linux/module.h> 146b291e80STanmay Shah #include <linux/of_address.h> 156b291e80STanmay Shah #include <linux/of_platform.h> 166b291e80STanmay Shah #include <linux/of_reserved_mem.h> 176b291e80STanmay Shah #include <linux/platform_device.h> 186b291e80STanmay Shah #include <linux/remoteproc.h> 196b291e80STanmay Shah 206b291e80STanmay Shah #include "remoteproc_internal.h" 216b291e80STanmay Shah 225dfb28c2STanmay Shah /* IPI buffer MAX length */ 235dfb28c2STanmay Shah #define IPI_BUF_LEN_MAX 32U 245dfb28c2STanmay Shah 255dfb28c2STanmay Shah /* RX mailbox client buffer max length */ 265dfb28c2STanmay Shah #define MBOX_CLIENT_BUF_MAX (IPI_BUF_LEN_MAX + \ 275dfb28c2STanmay Shah sizeof(struct zynqmp_ipi_message)) 286b291e80STanmay Shah /* 296b291e80STanmay Shah * settings for RPU cluster mode which 306b291e80STanmay Shah * reflects possible values of xlnx,cluster-mode dt-property 316b291e80STanmay Shah */ 326b291e80STanmay Shah enum zynqmp_r5_cluster_mode { 336b291e80STanmay Shah SPLIT_MODE = 0, /* When cores run as separate processor */ 346b291e80STanmay Shah LOCKSTEP_MODE = 1, /* cores execute same code in lockstep,clk-for-clk */ 356b291e80STanmay Shah SINGLE_CPU_MODE = 2, /* core0 is held in reset and only core1 runs */ 366b291e80STanmay Shah }; 376b291e80STanmay Shah 386b291e80STanmay Shah /** 396b291e80STanmay Shah * struct mem_bank_data - Memory Bank description 406b291e80STanmay Shah * 416b291e80STanmay Shah * @addr: Start address of memory bank 426013727fSTanmay Shah * @da: device address 436b291e80STanmay Shah * @size: Size of Memory bank 446b291e80STanmay Shah * @pm_domain_id: Power-domains id of memory bank for firmware to turn on/off 456b291e80STanmay Shah * @bank_name: name of the bank for remoteproc framework 466b291e80STanmay Shah */ 476b291e80STanmay Shah struct mem_bank_data { 486b291e80STanmay Shah phys_addr_t addr; 496013727fSTanmay Shah u32 da; 506b291e80STanmay Shah size_t size; 516b291e80STanmay Shah u32 pm_domain_id; 526b291e80STanmay Shah char *bank_name; 536b291e80STanmay Shah }; 546b291e80STanmay Shah 555dfb28c2STanmay Shah /** 565dfb28c2STanmay Shah * struct mbox_info 575dfb28c2STanmay Shah * 585dfb28c2STanmay Shah * @rx_mc_buf: to copy data from mailbox rx channel 595dfb28c2STanmay Shah * @tx_mc_buf: to copy data to mailbox tx channel 605dfb28c2STanmay Shah * @r5_core: this mailbox's corresponding r5_core pointer 615dfb28c2STanmay Shah * @mbox_work: schedule work after receiving data from mailbox 625dfb28c2STanmay Shah * @mbox_cl: mailbox client 635dfb28c2STanmay Shah * @tx_chan: mailbox tx channel 645dfb28c2STanmay Shah * @rx_chan: mailbox rx channel 655dfb28c2STanmay Shah */ 665dfb28c2STanmay Shah struct mbox_info { 675dfb28c2STanmay Shah unsigned char rx_mc_buf[MBOX_CLIENT_BUF_MAX]; 685dfb28c2STanmay Shah unsigned char tx_mc_buf[MBOX_CLIENT_BUF_MAX]; 695dfb28c2STanmay Shah struct zynqmp_r5_core *r5_core; 705dfb28c2STanmay Shah struct work_struct mbox_work; 715dfb28c2STanmay Shah struct mbox_client mbox_cl; 725dfb28c2STanmay Shah struct mbox_chan *tx_chan; 735dfb28c2STanmay Shah struct mbox_chan *rx_chan; 745dfb28c2STanmay Shah }; 755dfb28c2STanmay Shah 766b291e80STanmay Shah /* 7772c350c9STanmay Shah * Hardcoded TCM bank values. This will stay in driver to maintain backward 7872c350c9STanmay Shah * compatibility with device-tree that does not have TCM information. 796b291e80STanmay Shah */ 809af45bbdSTanmay Shah static const struct mem_bank_data zynqmp_tcm_banks_split[] = { 816013727fSTanmay Shah {0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ 826013727fSTanmay Shah {0xffe20000UL, 0x20000, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, 836013727fSTanmay Shah {0xffe90000UL, 0x0, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, 846013727fSTanmay Shah {0xffeb0000UL, 0x20000, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, 856b291e80STanmay Shah }; 866b291e80STanmay Shah 87b31bcda5STanmay Shah /* In lockstep mode cluster uses each 64KB TCM from second core as well */ 889af45bbdSTanmay Shah static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = { 89b31bcda5STanmay Shah {0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ 90b31bcda5STanmay Shah {0xffe20000UL, 0x20000, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, 91b31bcda5STanmay Shah {0xffe10000UL, 0x10000, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, 92b31bcda5STanmay Shah {0xffe30000UL, 0x30000, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, 939af45bbdSTanmay Shah }; 949af45bbdSTanmay Shah 956b291e80STanmay Shah /** 966b291e80STanmay Shah * struct zynqmp_r5_core 976b291e80STanmay Shah * 986b291e80STanmay Shah * @dev: device of RPU instance 996b291e80STanmay Shah * @np: device node of RPU instance 1006b291e80STanmay Shah * @tcm_bank_count: number TCM banks accessible to this RPU 1016b291e80STanmay Shah * @tcm_banks: array of each TCM bank data 1026b291e80STanmay Shah * @rproc: rproc handle 1036b291e80STanmay Shah * @pm_domain_id: RPU CPU power domain id 1045dfb28c2STanmay Shah * @ipi: pointer to mailbox information 1056b291e80STanmay Shah */ 1066b291e80STanmay Shah struct zynqmp_r5_core { 1076b291e80STanmay Shah struct device *dev; 1086b291e80STanmay Shah struct device_node *np; 1096b291e80STanmay Shah int tcm_bank_count; 1106b291e80STanmay Shah struct mem_bank_data **tcm_banks; 1116b291e80STanmay Shah struct rproc *rproc; 1126b291e80STanmay Shah u32 pm_domain_id; 1135dfb28c2STanmay Shah struct mbox_info *ipi; 1146b291e80STanmay Shah }; 1156b291e80STanmay Shah 1166b291e80STanmay Shah /** 1176b291e80STanmay Shah * struct zynqmp_r5_cluster 1186b291e80STanmay Shah * 1196b291e80STanmay Shah * @dev: r5f subsystem cluster device node 1206b291e80STanmay Shah * @mode: cluster mode of type zynqmp_r5_cluster_mode 1216b291e80STanmay Shah * @core_count: number of r5 cores used for this cluster mode 1226b291e80STanmay Shah * @r5_cores: Array of pointers pointing to r5 core 1236b291e80STanmay Shah */ 1246b291e80STanmay Shah struct zynqmp_r5_cluster { 1256b291e80STanmay Shah struct device *dev; 1266b291e80STanmay Shah enum zynqmp_r5_cluster_mode mode; 1276b291e80STanmay Shah int core_count; 1286b291e80STanmay Shah struct zynqmp_r5_core **r5_cores; 1296b291e80STanmay Shah }; 1306b291e80STanmay Shah 1315dfb28c2STanmay Shah /** 1325dfb28c2STanmay Shah * event_notified_idr_cb() - callback for vq_interrupt per notifyid 1335dfb28c2STanmay Shah * @id: rproc->notify id 1345dfb28c2STanmay Shah * @ptr: pointer to idr private data 1355dfb28c2STanmay Shah * @data: data passed to idr_for_each callback 1365dfb28c2STanmay Shah * 1375dfb28c2STanmay Shah * Pass notification to remoteproc virtio 1385dfb28c2STanmay Shah * 1395dfb28c2STanmay Shah * Return: 0. having return is to satisfy the idr_for_each() function 1405dfb28c2STanmay Shah * pointer input argument requirement. 1415dfb28c2STanmay Shah **/ 1425dfb28c2STanmay Shah static int event_notified_idr_cb(int id, void *ptr, void *data) 1435dfb28c2STanmay Shah { 1445dfb28c2STanmay Shah struct rproc *rproc = data; 1455dfb28c2STanmay Shah 1465dfb28c2STanmay Shah if (rproc_vq_interrupt(rproc, id) == IRQ_NONE) 1475dfb28c2STanmay Shah dev_dbg(&rproc->dev, "data not found for vqid=%d\n", id); 1485dfb28c2STanmay Shah 1495dfb28c2STanmay Shah return 0; 1505dfb28c2STanmay Shah } 1515dfb28c2STanmay Shah 1525dfb28c2STanmay Shah /** 1535dfb28c2STanmay Shah * handle_event_notified() - remoteproc notification work function 1545dfb28c2STanmay Shah * @work: pointer to the work structure 1555dfb28c2STanmay Shah * 1565dfb28c2STanmay Shah * It checks each registered remoteproc notify IDs. 1575dfb28c2STanmay Shah */ 1585dfb28c2STanmay Shah static void handle_event_notified(struct work_struct *work) 1595dfb28c2STanmay Shah { 1605dfb28c2STanmay Shah struct mbox_info *ipi; 1615dfb28c2STanmay Shah struct rproc *rproc; 1625dfb28c2STanmay Shah 1635dfb28c2STanmay Shah ipi = container_of(work, struct mbox_info, mbox_work); 1645dfb28c2STanmay Shah rproc = ipi->r5_core->rproc; 1655dfb28c2STanmay Shah 1665dfb28c2STanmay Shah /* 1675dfb28c2STanmay Shah * We only use IPI for interrupt. The RPU firmware side may or may 1685dfb28c2STanmay Shah * not write the notifyid when it trigger IPI. 1695dfb28c2STanmay Shah * And thus, we scan through all the registered notifyids and 1705dfb28c2STanmay Shah * find which one is valid to get the message. 1715dfb28c2STanmay Shah * Even if message from firmware is NULL, we attempt to get vqid 1725dfb28c2STanmay Shah */ 1735dfb28c2STanmay Shah idr_for_each(&rproc->notifyids, event_notified_idr_cb, rproc); 1745dfb28c2STanmay Shah } 1755dfb28c2STanmay Shah 1765dfb28c2STanmay Shah /** 1775dfb28c2STanmay Shah * zynqmp_r5_mb_rx_cb() - receive channel mailbox callback 1785dfb28c2STanmay Shah * @cl: mailbox client 1795dfb28c2STanmay Shah * @msg: message pointer 1805dfb28c2STanmay Shah * 1815dfb28c2STanmay Shah * Receive data from ipi buffer, ack interrupt and then 1825dfb28c2STanmay Shah * it will schedule the R5 notification work. 1835dfb28c2STanmay Shah */ 1845dfb28c2STanmay Shah static void zynqmp_r5_mb_rx_cb(struct mbox_client *cl, void *msg) 1855dfb28c2STanmay Shah { 1865dfb28c2STanmay Shah struct zynqmp_ipi_message *ipi_msg, *buf_msg; 1875dfb28c2STanmay Shah struct mbox_info *ipi; 1885dfb28c2STanmay Shah size_t len; 1895dfb28c2STanmay Shah 1905dfb28c2STanmay Shah ipi = container_of(cl, struct mbox_info, mbox_cl); 1915dfb28c2STanmay Shah 1925dfb28c2STanmay Shah /* copy data from ipi buffer to r5_core */ 1935dfb28c2STanmay Shah ipi_msg = (struct zynqmp_ipi_message *)msg; 1945dfb28c2STanmay Shah buf_msg = (struct zynqmp_ipi_message *)ipi->rx_mc_buf; 1955dfb28c2STanmay Shah len = ipi_msg->len; 1965dfb28c2STanmay Shah if (len > IPI_BUF_LEN_MAX) { 1975dfb28c2STanmay Shah dev_warn(cl->dev, "msg size exceeded than %d\n", 1985dfb28c2STanmay Shah IPI_BUF_LEN_MAX); 1995dfb28c2STanmay Shah len = IPI_BUF_LEN_MAX; 2005dfb28c2STanmay Shah } 2015dfb28c2STanmay Shah buf_msg->len = len; 2025dfb28c2STanmay Shah memcpy(buf_msg->data, ipi_msg->data, len); 2035dfb28c2STanmay Shah 2045dfb28c2STanmay Shah /* received and processed interrupt ack */ 2055dfb28c2STanmay Shah if (mbox_send_message(ipi->rx_chan, NULL) < 0) 2065dfb28c2STanmay Shah dev_err(cl->dev, "ack failed to mbox rx_chan\n"); 2075dfb28c2STanmay Shah 2085dfb28c2STanmay Shah schedule_work(&ipi->mbox_work); 2095dfb28c2STanmay Shah } 2105dfb28c2STanmay Shah 2115dfb28c2STanmay Shah /** 2125dfb28c2STanmay Shah * zynqmp_r5_setup_mbox() - Setup mailboxes related properties 2135dfb28c2STanmay Shah * this is used for each individual R5 core 2145dfb28c2STanmay Shah * 2155dfb28c2STanmay Shah * @cdev: child node device 2165dfb28c2STanmay Shah * 2175dfb28c2STanmay Shah * Function to setup mailboxes related properties 2185dfb28c2STanmay Shah * return : NULL if failed else pointer to mbox_info 2195dfb28c2STanmay Shah */ 2205dfb28c2STanmay Shah static struct mbox_info *zynqmp_r5_setup_mbox(struct device *cdev) 2215dfb28c2STanmay Shah { 2225dfb28c2STanmay Shah struct mbox_client *mbox_cl; 2235dfb28c2STanmay Shah struct mbox_info *ipi; 2245dfb28c2STanmay Shah 2255dfb28c2STanmay Shah ipi = kzalloc(sizeof(*ipi), GFP_KERNEL); 2265dfb28c2STanmay Shah if (!ipi) 2275dfb28c2STanmay Shah return NULL; 2285dfb28c2STanmay Shah 2295dfb28c2STanmay Shah mbox_cl = &ipi->mbox_cl; 2305dfb28c2STanmay Shah mbox_cl->rx_callback = zynqmp_r5_mb_rx_cb; 2315dfb28c2STanmay Shah mbox_cl->tx_block = false; 2325dfb28c2STanmay Shah mbox_cl->knows_txdone = false; 2335dfb28c2STanmay Shah mbox_cl->tx_done = NULL; 2345dfb28c2STanmay Shah mbox_cl->dev = cdev; 2355dfb28c2STanmay Shah 2365dfb28c2STanmay Shah /* Request TX and RX channels */ 2375dfb28c2STanmay Shah ipi->tx_chan = mbox_request_channel_byname(mbox_cl, "tx"); 2385dfb28c2STanmay Shah if (IS_ERR(ipi->tx_chan)) { 2395dfb28c2STanmay Shah ipi->tx_chan = NULL; 2405dfb28c2STanmay Shah kfree(ipi); 2415dfb28c2STanmay Shah dev_warn(cdev, "mbox tx channel request failed\n"); 2425dfb28c2STanmay Shah return NULL; 2435dfb28c2STanmay Shah } 2445dfb28c2STanmay Shah 2455dfb28c2STanmay Shah ipi->rx_chan = mbox_request_channel_byname(mbox_cl, "rx"); 2465dfb28c2STanmay Shah if (IS_ERR(ipi->rx_chan)) { 2475dfb28c2STanmay Shah mbox_free_channel(ipi->tx_chan); 2485dfb28c2STanmay Shah ipi->rx_chan = NULL; 2495dfb28c2STanmay Shah ipi->tx_chan = NULL; 2505dfb28c2STanmay Shah kfree(ipi); 2515dfb28c2STanmay Shah dev_warn(cdev, "mbox rx channel request failed\n"); 2525dfb28c2STanmay Shah return NULL; 2535dfb28c2STanmay Shah } 2545dfb28c2STanmay Shah 2555dfb28c2STanmay Shah INIT_WORK(&ipi->mbox_work, handle_event_notified); 2565dfb28c2STanmay Shah 2575dfb28c2STanmay Shah return ipi; 2585dfb28c2STanmay Shah } 2595dfb28c2STanmay Shah 2605dfb28c2STanmay Shah static void zynqmp_r5_free_mbox(struct mbox_info *ipi) 2615dfb28c2STanmay Shah { 2625dfb28c2STanmay Shah if (!ipi) 2635dfb28c2STanmay Shah return; 2645dfb28c2STanmay Shah 2655dfb28c2STanmay Shah if (ipi->tx_chan) { 2665dfb28c2STanmay Shah mbox_free_channel(ipi->tx_chan); 2675dfb28c2STanmay Shah ipi->tx_chan = NULL; 2685dfb28c2STanmay Shah } 2695dfb28c2STanmay Shah 2705dfb28c2STanmay Shah if (ipi->rx_chan) { 2715dfb28c2STanmay Shah mbox_free_channel(ipi->rx_chan); 2725dfb28c2STanmay Shah ipi->rx_chan = NULL; 2735dfb28c2STanmay Shah } 2745dfb28c2STanmay Shah 2755dfb28c2STanmay Shah kfree(ipi); 2765dfb28c2STanmay Shah } 2775dfb28c2STanmay Shah 2785dfb28c2STanmay Shah /* 2795dfb28c2STanmay Shah * zynqmp_r5_core_kick() - kick a firmware if mbox is provided 2805dfb28c2STanmay Shah * @rproc: r5 core's corresponding rproc structure 2815dfb28c2STanmay Shah * @vqid: virtqueue ID 2825dfb28c2STanmay Shah */ 2835dfb28c2STanmay Shah static void zynqmp_r5_rproc_kick(struct rproc *rproc, int vqid) 2845dfb28c2STanmay Shah { 2855dfb28c2STanmay Shah struct zynqmp_r5_core *r5_core = rproc->priv; 2865dfb28c2STanmay Shah struct device *dev = r5_core->dev; 2875dfb28c2STanmay Shah struct zynqmp_ipi_message *mb_msg; 2885dfb28c2STanmay Shah struct mbox_info *ipi; 2895dfb28c2STanmay Shah int ret; 2905dfb28c2STanmay Shah 2915dfb28c2STanmay Shah ipi = r5_core->ipi; 2925dfb28c2STanmay Shah if (!ipi) 2935dfb28c2STanmay Shah return; 2945dfb28c2STanmay Shah 2955dfb28c2STanmay Shah mb_msg = (struct zynqmp_ipi_message *)ipi->tx_mc_buf; 2965dfb28c2STanmay Shah memcpy(mb_msg->data, &vqid, sizeof(vqid)); 2975dfb28c2STanmay Shah mb_msg->len = sizeof(vqid); 2985dfb28c2STanmay Shah ret = mbox_send_message(ipi->tx_chan, mb_msg); 2995dfb28c2STanmay Shah if (ret < 0) 3005dfb28c2STanmay Shah dev_warn(dev, "failed to send message\n"); 3015dfb28c2STanmay Shah } 3025dfb28c2STanmay Shah 3036b291e80STanmay Shah /* 3046b291e80STanmay Shah * zynqmp_r5_rproc_start() 3056b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 3066b291e80STanmay Shah * 3076b291e80STanmay Shah * Start R5 Core from designated boot address. 3086b291e80STanmay Shah * 3096b291e80STanmay Shah * return 0 on success, otherwise non-zero value on failure 3106b291e80STanmay Shah */ 3116b291e80STanmay Shah static int zynqmp_r5_rproc_start(struct rproc *rproc) 3126b291e80STanmay Shah { 3136b291e80STanmay Shah struct zynqmp_r5_core *r5_core = rproc->priv; 3146b291e80STanmay Shah enum rpu_boot_mem bootmem; 3156b291e80STanmay Shah int ret; 3166b291e80STanmay Shah 3176b291e80STanmay Shah /* 3186b291e80STanmay Shah * The exception vector pointers (EVP) refer to the base-address of 3196b291e80STanmay Shah * exception vectors (for reset, IRQ, FIQ, etc). The reset-vector 3206b291e80STanmay Shah * starts at the base-address and subsequent vectors are on 4-byte 3216b291e80STanmay Shah * boundaries. 3226b291e80STanmay Shah * 3236b291e80STanmay Shah * Exception vectors can start either from 0x0000_0000 (LOVEC) or 3246b291e80STanmay Shah * from 0xFFFF_0000 (HIVEC) which is mapped in the OCM (On-Chip Memory) 3256b291e80STanmay Shah * 3266b291e80STanmay Shah * Usually firmware will put Exception vectors at LOVEC. 3276b291e80STanmay Shah * 3286b291e80STanmay Shah * It is not recommend that you change the exception vector. 3296b291e80STanmay Shah * Changing the EVP to HIVEC will result in increased interrupt latency 3306b291e80STanmay Shah * and jitter. Also, if the OCM is secured and the Cortex-R5F processor 3316b291e80STanmay Shah * is non-secured, then the Cortex-R5F processor cannot access the 3326b291e80STanmay Shah * HIVEC exception vectors in the OCM. 3336b291e80STanmay Shah */ 3346b291e80STanmay Shah bootmem = (rproc->bootaddr >= 0xFFFC0000) ? 3356b291e80STanmay Shah PM_RPU_BOOTMEM_HIVEC : PM_RPU_BOOTMEM_LOVEC; 3366b291e80STanmay Shah 3376b291e80STanmay Shah dev_dbg(r5_core->dev, "RPU boot addr 0x%llx from %s.", rproc->bootaddr, 3386b291e80STanmay Shah bootmem == PM_RPU_BOOTMEM_HIVEC ? "OCM" : "TCM"); 3396b291e80STanmay Shah 3406b291e80STanmay Shah ret = zynqmp_pm_request_wake(r5_core->pm_domain_id, 1, 3416b291e80STanmay Shah bootmem, ZYNQMP_PM_REQUEST_ACK_NO); 3426b291e80STanmay Shah if (ret) 3436b291e80STanmay Shah dev_err(r5_core->dev, 3446b291e80STanmay Shah "failed to start RPU = 0x%x\n", r5_core->pm_domain_id); 3456b291e80STanmay Shah return ret; 3466b291e80STanmay Shah } 3476b291e80STanmay Shah 3486b291e80STanmay Shah /* 3496b291e80STanmay Shah * zynqmp_r5_rproc_stop() 3506b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 3516b291e80STanmay Shah * 3526b291e80STanmay Shah * Power down R5 Core. 3536b291e80STanmay Shah * 3546b291e80STanmay Shah * return 0 on success, otherwise non-zero value on failure 3556b291e80STanmay Shah */ 3566b291e80STanmay Shah static int zynqmp_r5_rproc_stop(struct rproc *rproc) 3576b291e80STanmay Shah { 3586b291e80STanmay Shah struct zynqmp_r5_core *r5_core = rproc->priv; 3596b291e80STanmay Shah int ret; 3606b291e80STanmay Shah 3616b291e80STanmay Shah ret = zynqmp_pm_force_pwrdwn(r5_core->pm_domain_id, 3626b291e80STanmay Shah ZYNQMP_PM_REQUEST_ACK_BLOCKING); 3636b291e80STanmay Shah if (ret) 3646b291e80STanmay Shah dev_err(r5_core->dev, "failed to stop remoteproc RPU %d\n", ret); 3656b291e80STanmay Shah 3666b291e80STanmay Shah return ret; 3676b291e80STanmay Shah } 3686b291e80STanmay Shah 3696b291e80STanmay Shah /* 3706b291e80STanmay Shah * zynqmp_r5_mem_region_map() 3716b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 3726b291e80STanmay Shah * @mem: mem descriptor to map reserved memory-regions 3736b291e80STanmay Shah * 3746b291e80STanmay Shah * Callback to map va for memory-region's carveout. 3756b291e80STanmay Shah * 3766b291e80STanmay Shah * return 0 on success, otherwise non-zero value on failure 3776b291e80STanmay Shah */ 3786b291e80STanmay Shah static int zynqmp_r5_mem_region_map(struct rproc *rproc, 3796b291e80STanmay Shah struct rproc_mem_entry *mem) 3806b291e80STanmay Shah { 3816b291e80STanmay Shah void __iomem *va; 3826b291e80STanmay Shah 3836b291e80STanmay Shah va = ioremap_wc(mem->dma, mem->len); 3846b291e80STanmay Shah if (IS_ERR_OR_NULL(va)) 3856b291e80STanmay Shah return -ENOMEM; 3866b291e80STanmay Shah 3876b291e80STanmay Shah mem->va = (void *)va; 3886b291e80STanmay Shah 3896b291e80STanmay Shah return 0; 3906b291e80STanmay Shah } 3916b291e80STanmay Shah 3926b291e80STanmay Shah /* 3936b291e80STanmay Shah * zynqmp_r5_rproc_mem_unmap 3946b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 3956b291e80STanmay Shah * @mem: mem entry to unmap 3966b291e80STanmay Shah * 3976b291e80STanmay Shah * Unmap memory-region carveout 3986b291e80STanmay Shah * 3996b291e80STanmay Shah * return: always returns 0 4006b291e80STanmay Shah */ 4016b291e80STanmay Shah static int zynqmp_r5_mem_region_unmap(struct rproc *rproc, 4026b291e80STanmay Shah struct rproc_mem_entry *mem) 4036b291e80STanmay Shah { 4046b291e80STanmay Shah iounmap((void __iomem *)mem->va); 4056b291e80STanmay Shah return 0; 4066b291e80STanmay Shah } 4076b291e80STanmay Shah 4086b291e80STanmay Shah /* 4096b291e80STanmay Shah * add_mem_regions_carveout() 4106b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 4116b291e80STanmay Shah * 4126b291e80STanmay Shah * Construct rproc mem carveouts from memory-region property nodes 4136b291e80STanmay Shah * 4146b291e80STanmay Shah * return 0 on success, otherwise non-zero value on failure 4156b291e80STanmay Shah */ 4166b291e80STanmay Shah static int add_mem_regions_carveout(struct rproc *rproc) 4176b291e80STanmay Shah { 4186b291e80STanmay Shah struct rproc_mem_entry *rproc_mem; 4196b291e80STanmay Shah struct zynqmp_r5_core *r5_core; 42081c18e08STanmay Shah struct of_phandle_iterator it; 4216b291e80STanmay Shah struct reserved_mem *rmem; 42281c18e08STanmay Shah int i = 0; 4236b291e80STanmay Shah 42486660713SYu Zhe r5_core = rproc->priv; 4256b291e80STanmay Shah 42681c18e08STanmay Shah /* Register associated reserved memory regions */ 42781c18e08STanmay Shah of_phandle_iterator_init(&it, r5_core->np, "memory-region", NULL, 0); 4286b291e80STanmay Shah 42981c18e08STanmay Shah while (of_phandle_iterator_next(&it) == 0) { 43081c18e08STanmay Shah rmem = of_reserved_mem_lookup(it.node); 43181c18e08STanmay Shah if (!rmem) { 43281c18e08STanmay Shah of_node_put(it.node); 43381c18e08STanmay Shah dev_err(&rproc->dev, "unable to acquire memory-region\n"); 43481c18e08STanmay Shah return -EINVAL; 43581c18e08STanmay Shah } 43681c18e08STanmay Shah 43781c18e08STanmay Shah if (!strcmp(it.node->name, "vdev0buffer")) { 4386b291e80STanmay Shah /* Init reserved memory for vdev buffer */ 4396b291e80STanmay Shah rproc_mem = rproc_of_resm_mem_entry_init(&rproc->dev, i, 4406b291e80STanmay Shah rmem->size, 4416b291e80STanmay Shah rmem->base, 44281c18e08STanmay Shah it.node->name); 4436b291e80STanmay Shah } else { 4446b291e80STanmay Shah /* Register associated reserved memory regions */ 4456b291e80STanmay Shah rproc_mem = rproc_mem_entry_init(&rproc->dev, NULL, 4466b291e80STanmay Shah (dma_addr_t)rmem->base, 4476b291e80STanmay Shah rmem->size, rmem->base, 4486b291e80STanmay Shah zynqmp_r5_mem_region_map, 4496b291e80STanmay Shah zynqmp_r5_mem_region_unmap, 45081c18e08STanmay Shah it.node->name); 4516b291e80STanmay Shah } 4526b291e80STanmay Shah 45381c18e08STanmay Shah if (!rproc_mem) { 45481c18e08STanmay Shah of_node_put(it.node); 4556b291e80STanmay Shah return -ENOMEM; 45681c18e08STanmay Shah } 4576b291e80STanmay Shah 4586b291e80STanmay Shah rproc_add_carveout(rproc, rproc_mem); 459fec2601fSLeonard Crestez rproc_coredump_add_segment(rproc, rmem->base, rmem->size); 4606b291e80STanmay Shah 4616b291e80STanmay Shah dev_dbg(&rproc->dev, "reserved mem carveout %s addr=%llx, size=0x%llx", 46281c18e08STanmay Shah it.node->name, rmem->base, rmem->size); 46381c18e08STanmay Shah i++; 4646b291e80STanmay Shah } 4656b291e80STanmay Shah 4666b291e80STanmay Shah return 0; 4676b291e80STanmay Shah } 4686b291e80STanmay Shah 4696b291e80STanmay Shah /* 4706b291e80STanmay Shah * tcm_mem_unmap() 4716b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 4726b291e80STanmay Shah * @mem: tcm mem entry to unmap 4736b291e80STanmay Shah * 4746b291e80STanmay Shah * Unmap TCM banks when powering down R5 core. 4756b291e80STanmay Shah * 4766b291e80STanmay Shah * return always 0 4776b291e80STanmay Shah */ 4786b291e80STanmay Shah static int tcm_mem_unmap(struct rproc *rproc, struct rproc_mem_entry *mem) 4796b291e80STanmay Shah { 4806b291e80STanmay Shah iounmap((void __iomem *)mem->va); 4816b291e80STanmay Shah 4826b291e80STanmay Shah return 0; 4836b291e80STanmay Shah } 4846b291e80STanmay Shah 4856b291e80STanmay Shah /* 4866b291e80STanmay Shah * tcm_mem_map() 4876b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 4886b291e80STanmay Shah * @mem: tcm memory entry descriptor 4896b291e80STanmay Shah * 4906b291e80STanmay Shah * Given TCM bank entry, this func setup virtual address for TCM bank 4916b291e80STanmay Shah * remoteproc carveout. It also takes care of va to da address translation 4926b291e80STanmay Shah * 4936b291e80STanmay Shah * return 0 on success, otherwise non-zero value on failure 4946b291e80STanmay Shah */ 4956b291e80STanmay Shah static int tcm_mem_map(struct rproc *rproc, 4966b291e80STanmay Shah struct rproc_mem_entry *mem) 4976b291e80STanmay Shah { 4986b291e80STanmay Shah void __iomem *va; 4996b291e80STanmay Shah 5006b291e80STanmay Shah va = ioremap_wc(mem->dma, mem->len); 5016b291e80STanmay Shah if (IS_ERR_OR_NULL(va)) 5026b291e80STanmay Shah return -ENOMEM; 5036b291e80STanmay Shah 5046b291e80STanmay Shah /* Update memory entry va */ 5056b291e80STanmay Shah mem->va = (void *)va; 5066b291e80STanmay Shah 5076b291e80STanmay Shah /* clear TCMs */ 5086b291e80STanmay Shah memset_io(va, 0, mem->len); 5096b291e80STanmay Shah 5106b291e80STanmay Shah return 0; 5116b291e80STanmay Shah } 5126b291e80STanmay Shah 5136b291e80STanmay Shah /* 514b31bcda5STanmay Shah * add_tcm_banks() 5156b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 5166b291e80STanmay Shah * 517b31bcda5STanmay Shah * allocate and add remoteproc carveout for TCM memory 5186b291e80STanmay Shah * 5196b291e80STanmay Shah * return 0 on success, otherwise non-zero value on failure 5206b291e80STanmay Shah */ 521b31bcda5STanmay Shah static int add_tcm_banks(struct rproc *rproc) 5226b291e80STanmay Shah { 5236b291e80STanmay Shah struct rproc_mem_entry *rproc_mem; 5246b291e80STanmay Shah struct zynqmp_r5_core *r5_core; 5256b291e80STanmay Shah int i, num_banks, ret; 5266b291e80STanmay Shah phys_addr_t bank_addr; 5276b291e80STanmay Shah struct device *dev; 5286b291e80STanmay Shah u32 pm_domain_id; 5296b291e80STanmay Shah size_t bank_size; 5306b291e80STanmay Shah char *bank_name; 5316013727fSTanmay Shah u32 da; 5326b291e80STanmay Shah 53386660713SYu Zhe r5_core = rproc->priv; 5346b291e80STanmay Shah dev = r5_core->dev; 5356b291e80STanmay Shah num_banks = r5_core->tcm_bank_count; 5366b291e80STanmay Shah 5376b291e80STanmay Shah /* 5386b291e80STanmay Shah * Power-on Each 64KB TCM, 5396b291e80STanmay Shah * register its address space, map and unmap functions 5406b291e80STanmay Shah * and add carveouts accordingly 5416b291e80STanmay Shah */ 5426b291e80STanmay Shah for (i = 0; i < num_banks; i++) { 5436b291e80STanmay Shah bank_addr = r5_core->tcm_banks[i]->addr; 5446013727fSTanmay Shah da = r5_core->tcm_banks[i]->da; 5456b291e80STanmay Shah bank_name = r5_core->tcm_banks[i]->bank_name; 5466b291e80STanmay Shah bank_size = r5_core->tcm_banks[i]->size; 5476b291e80STanmay Shah pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 5486b291e80STanmay Shah 5496b291e80STanmay Shah ret = zynqmp_pm_request_node(pm_domain_id, 5506b291e80STanmay Shah ZYNQMP_PM_CAPABILITY_ACCESS, 0, 5516b291e80STanmay Shah ZYNQMP_PM_REQUEST_ACK_BLOCKING); 5526b291e80STanmay Shah if (ret < 0) { 5536b291e80STanmay Shah dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); 554b31bcda5STanmay Shah goto release_tcm; 5556b291e80STanmay Shah } 5566b291e80STanmay Shah 557b31bcda5STanmay Shah dev_dbg(dev, "TCM carveout %s addr=%llx, da=0x%x, size=0x%lx", 5586013727fSTanmay Shah bank_name, bank_addr, da, bank_size); 5596b291e80STanmay Shah 5606b291e80STanmay Shah rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, 5616013727fSTanmay Shah bank_size, da, 5626b291e80STanmay Shah tcm_mem_map, tcm_mem_unmap, 5636b291e80STanmay Shah bank_name); 5646b291e80STanmay Shah if (!rproc_mem) { 5656b291e80STanmay Shah ret = -ENOMEM; 5666b291e80STanmay Shah zynqmp_pm_release_node(pm_domain_id); 567b31bcda5STanmay Shah goto release_tcm; 5686b291e80STanmay Shah } 5696b291e80STanmay Shah 5706b291e80STanmay Shah rproc_add_carveout(rproc, rproc_mem); 571fec2601fSLeonard Crestez rproc_coredump_add_segment(rproc, da, bank_size); 5726b291e80STanmay Shah } 5736b291e80STanmay Shah 5746b291e80STanmay Shah return 0; 5756b291e80STanmay Shah 576b31bcda5STanmay Shah release_tcm: 5776b291e80STanmay Shah /* If failed, Turn off all TCM banks turned on before */ 5786b291e80STanmay Shah for (i--; i >= 0; i--) { 5796b291e80STanmay Shah pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 5806b291e80STanmay Shah zynqmp_pm_release_node(pm_domain_id); 5816b291e80STanmay Shah } 5826b291e80STanmay Shah return ret; 5836b291e80STanmay Shah } 5846b291e80STanmay Shah 5856b291e80STanmay Shah /* 5866b291e80STanmay Shah * zynqmp_r5_parse_fw() 5876b291e80STanmay Shah * @rproc: single R5 core's corresponding rproc instance 5886b291e80STanmay Shah * @fw: ptr to firmware to be loaded onto r5 core 5896b291e80STanmay Shah * 5906b291e80STanmay Shah * get resource table if available 5916b291e80STanmay Shah * 5926b291e80STanmay Shah * return 0 on success, otherwise non-zero value on failure 5936b291e80STanmay Shah */ 5946b291e80STanmay Shah static int zynqmp_r5_parse_fw(struct rproc *rproc, const struct firmware *fw) 5956b291e80STanmay Shah { 5966b291e80STanmay Shah int ret; 5976b291e80STanmay Shah 5986b291e80STanmay Shah ret = rproc_elf_load_rsc_table(rproc, fw); 5996b291e80STanmay Shah if (ret == -EINVAL) { 6006b291e80STanmay Shah /* 6016b291e80STanmay Shah * resource table only required for IPC. 6026b291e80STanmay Shah * if not present, this is not necessarily an error; 6036b291e80STanmay Shah * for example, loading r5 hello world application 6046b291e80STanmay Shah * so simply inform user and keep going. 6056b291e80STanmay Shah */ 6066b291e80STanmay Shah dev_info(&rproc->dev, "no resource table found.\n"); 6076b291e80STanmay Shah ret = 0; 6086b291e80STanmay Shah } 6096b291e80STanmay Shah return ret; 6106b291e80STanmay Shah } 6116b291e80STanmay Shah 6126b291e80STanmay Shah /** 6136b291e80STanmay Shah * zynqmp_r5_rproc_prepare() 6146b291e80STanmay Shah * adds carveouts for TCM bank and reserved memory regions 6156b291e80STanmay Shah * 6166b291e80STanmay Shah * @rproc: Device node of each rproc 6176b291e80STanmay Shah * 6186b291e80STanmay Shah * Return: 0 for success else < 0 error code 6196b291e80STanmay Shah */ 6206b291e80STanmay Shah static int zynqmp_r5_rproc_prepare(struct rproc *rproc) 6216b291e80STanmay Shah { 6226b291e80STanmay Shah int ret; 6236b291e80STanmay Shah 6246b291e80STanmay Shah ret = add_tcm_banks(rproc); 6256b291e80STanmay Shah if (ret) { 6266b291e80STanmay Shah dev_err(&rproc->dev, "failed to get TCM banks, err %d\n", ret); 6276b291e80STanmay Shah return ret; 6286b291e80STanmay Shah } 6296b291e80STanmay Shah 6306b291e80STanmay Shah ret = add_mem_regions_carveout(rproc); 6316b291e80STanmay Shah if (ret) { 6326b291e80STanmay Shah dev_err(&rproc->dev, "failed to get reserve mem regions %d\n", ret); 6336b291e80STanmay Shah return ret; 6346b291e80STanmay Shah } 6356b291e80STanmay Shah 6366b291e80STanmay Shah return 0; 6376b291e80STanmay Shah } 6386b291e80STanmay Shah 6396b291e80STanmay Shah /** 6406b291e80STanmay Shah * zynqmp_r5_rproc_unprepare() 6416b291e80STanmay Shah * Turns off TCM banks using power-domain id 6426b291e80STanmay Shah * 6436b291e80STanmay Shah * @rproc: Device node of each rproc 6446b291e80STanmay Shah * 6456b291e80STanmay Shah * Return: always 0 6466b291e80STanmay Shah */ 6476b291e80STanmay Shah static int zynqmp_r5_rproc_unprepare(struct rproc *rproc) 6486b291e80STanmay Shah { 6496b291e80STanmay Shah struct zynqmp_r5_core *r5_core; 6506b291e80STanmay Shah u32 pm_domain_id; 6516b291e80STanmay Shah int i; 6526b291e80STanmay Shah 65386660713SYu Zhe r5_core = rproc->priv; 6546b291e80STanmay Shah 6556b291e80STanmay Shah for (i = 0; i < r5_core->tcm_bank_count; i++) { 6566b291e80STanmay Shah pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; 6576b291e80STanmay Shah if (zynqmp_pm_release_node(pm_domain_id)) 6586b291e80STanmay Shah dev_warn(r5_core->dev, 6596b291e80STanmay Shah "can't turn off TCM bank 0x%x", pm_domain_id); 6606b291e80STanmay Shah } 6616b291e80STanmay Shah 6626b291e80STanmay Shah return 0; 6636b291e80STanmay Shah } 6646b291e80STanmay Shah 6656b291e80STanmay Shah static const struct rproc_ops zynqmp_r5_rproc_ops = { 6666b291e80STanmay Shah .prepare = zynqmp_r5_rproc_prepare, 6676b291e80STanmay Shah .unprepare = zynqmp_r5_rproc_unprepare, 6686b291e80STanmay Shah .start = zynqmp_r5_rproc_start, 6696b291e80STanmay Shah .stop = zynqmp_r5_rproc_stop, 6706b291e80STanmay Shah .load = rproc_elf_load_segments, 6716b291e80STanmay Shah .parse_fw = zynqmp_r5_parse_fw, 6726b291e80STanmay Shah .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, 6736b291e80STanmay Shah .sanity_check = rproc_elf_sanity_check, 6746b291e80STanmay Shah .get_boot_addr = rproc_elf_get_boot_addr, 6755dfb28c2STanmay Shah .kick = zynqmp_r5_rproc_kick, 6766b291e80STanmay Shah }; 6776b291e80STanmay Shah 6786b291e80STanmay Shah /** 6796b291e80STanmay Shah * zynqmp_r5_add_rproc_core() 6806b291e80STanmay Shah * Allocate and add struct rproc object for each r5f core 6816b291e80STanmay Shah * This is called for each individual r5f core 6826b291e80STanmay Shah * 6836b291e80STanmay Shah * @cdev: Device node of each r5 core 6846b291e80STanmay Shah * 6856b291e80STanmay Shah * Return: zynqmp_r5_core object for success else error code pointer 6866b291e80STanmay Shah */ 6876b291e80STanmay Shah static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) 6886b291e80STanmay Shah { 6896b291e80STanmay Shah struct zynqmp_r5_core *r5_core; 6906b291e80STanmay Shah struct rproc *r5_rproc; 6916b291e80STanmay Shah int ret; 6926b291e80STanmay Shah 6936b291e80STanmay Shah /* Set up DMA mask */ 6946b291e80STanmay Shah ret = dma_set_coherent_mask(cdev, DMA_BIT_MASK(32)); 6956b291e80STanmay Shah if (ret) 6966b291e80STanmay Shah return ERR_PTR(ret); 6976b291e80STanmay Shah 6986b291e80STanmay Shah /* Allocate remoteproc instance */ 6996b291e80STanmay Shah r5_rproc = rproc_alloc(cdev, dev_name(cdev), 7006b291e80STanmay Shah &zynqmp_r5_rproc_ops, 7016b291e80STanmay Shah NULL, sizeof(struct zynqmp_r5_core)); 7026b291e80STanmay Shah if (!r5_rproc) { 7036b291e80STanmay Shah dev_err(cdev, "failed to allocate memory for rproc instance\n"); 7046b291e80STanmay Shah return ERR_PTR(-ENOMEM); 7056b291e80STanmay Shah } 7066b291e80STanmay Shah 707fec2601fSLeonard Crestez rproc_coredump_set_elf_info(r5_rproc, ELFCLASS32, EM_ARM); 708fec2601fSLeonard Crestez 7096b291e80STanmay Shah r5_rproc->auto_boot = false; 71086660713SYu Zhe r5_core = r5_rproc->priv; 7116b291e80STanmay Shah r5_core->dev = cdev; 7126b291e80STanmay Shah r5_core->np = dev_of_node(cdev); 7136b291e80STanmay Shah if (!r5_core->np) { 7146b291e80STanmay Shah dev_err(cdev, "can't get device node for r5 core\n"); 7156b291e80STanmay Shah ret = -EINVAL; 7166b291e80STanmay Shah goto free_rproc; 7176b291e80STanmay Shah } 7186b291e80STanmay Shah 7196b291e80STanmay Shah /* Add R5 remoteproc core */ 7206b291e80STanmay Shah ret = rproc_add(r5_rproc); 7216b291e80STanmay Shah if (ret) { 7226b291e80STanmay Shah dev_err(cdev, "failed to add r5 remoteproc\n"); 7236b291e80STanmay Shah goto free_rproc; 7246b291e80STanmay Shah } 7256b291e80STanmay Shah 7266b291e80STanmay Shah r5_core->rproc = r5_rproc; 7276b291e80STanmay Shah return r5_core; 7286b291e80STanmay Shah 7296b291e80STanmay Shah free_rproc: 7306b291e80STanmay Shah rproc_free(r5_rproc); 7316b291e80STanmay Shah return ERR_PTR(ret); 7326b291e80STanmay Shah } 7336b291e80STanmay Shah 73472c350c9STanmay Shah static int zynqmp_r5_get_tcm_node_from_dt(struct zynqmp_r5_cluster *cluster) 73572c350c9STanmay Shah { 73672c350c9STanmay Shah int i, j, tcm_bank_count, ret, tcm_pd_idx, pd_count; 73772c350c9STanmay Shah struct of_phandle_args out_args; 73872c350c9STanmay Shah struct zynqmp_r5_core *r5_core; 73972c350c9STanmay Shah struct platform_device *cpdev; 74072c350c9STanmay Shah struct mem_bank_data *tcm; 74172c350c9STanmay Shah struct device_node *np; 74272c350c9STanmay Shah struct resource *res; 74372c350c9STanmay Shah u64 abs_addr, size; 74472c350c9STanmay Shah struct device *dev; 74572c350c9STanmay Shah 74672c350c9STanmay Shah for (i = 0; i < cluster->core_count; i++) { 74772c350c9STanmay Shah r5_core = cluster->r5_cores[i]; 74872c350c9STanmay Shah dev = r5_core->dev; 74972c350c9STanmay Shah np = r5_core->np; 75072c350c9STanmay Shah 75172c350c9STanmay Shah pd_count = of_count_phandle_with_args(np, "power-domains", 75272c350c9STanmay Shah "#power-domain-cells"); 75372c350c9STanmay Shah 75472c350c9STanmay Shah if (pd_count <= 0) { 75572c350c9STanmay Shah dev_err(dev, "invalid power-domains property, %d\n", pd_count); 75672c350c9STanmay Shah return -EINVAL; 75772c350c9STanmay Shah } 75872c350c9STanmay Shah 75972c350c9STanmay Shah /* First entry in power-domains list is for r5 core, rest for TCM. */ 76072c350c9STanmay Shah tcm_bank_count = pd_count - 1; 76172c350c9STanmay Shah 76272c350c9STanmay Shah if (tcm_bank_count <= 0) { 76372c350c9STanmay Shah dev_err(dev, "invalid TCM count %d\n", tcm_bank_count); 76472c350c9STanmay Shah return -EINVAL; 76572c350c9STanmay Shah } 76672c350c9STanmay Shah 76772c350c9STanmay Shah r5_core->tcm_banks = devm_kcalloc(dev, tcm_bank_count, 76872c350c9STanmay Shah sizeof(struct mem_bank_data *), 76972c350c9STanmay Shah GFP_KERNEL); 77072c350c9STanmay Shah if (!r5_core->tcm_banks) 77172c350c9STanmay Shah return -ENOMEM; 77272c350c9STanmay Shah 77372c350c9STanmay Shah r5_core->tcm_bank_count = tcm_bank_count; 77472c350c9STanmay Shah for (j = 0, tcm_pd_idx = 1; j < tcm_bank_count; j++, tcm_pd_idx++) { 77572c350c9STanmay Shah tcm = devm_kzalloc(dev, sizeof(struct mem_bank_data), 77672c350c9STanmay Shah GFP_KERNEL); 77772c350c9STanmay Shah if (!tcm) 77872c350c9STanmay Shah return -ENOMEM; 77972c350c9STanmay Shah 78072c350c9STanmay Shah r5_core->tcm_banks[j] = tcm; 78172c350c9STanmay Shah 78272c350c9STanmay Shah /* Get power-domains id of TCM. */ 78372c350c9STanmay Shah ret = of_parse_phandle_with_args(np, "power-domains", 78472c350c9STanmay Shah "#power-domain-cells", 78572c350c9STanmay Shah tcm_pd_idx, &out_args); 78672c350c9STanmay Shah if (ret) { 78772c350c9STanmay Shah dev_err(r5_core->dev, 78872c350c9STanmay Shah "failed to get tcm %d pm domain, ret %d\n", 78972c350c9STanmay Shah tcm_pd_idx, ret); 79072c350c9STanmay Shah return ret; 79172c350c9STanmay Shah } 79272c350c9STanmay Shah tcm->pm_domain_id = out_args.args[0]; 79372c350c9STanmay Shah of_node_put(out_args.np); 79472c350c9STanmay Shah 79572c350c9STanmay Shah /* Get TCM address without translation. */ 79672c350c9STanmay Shah ret = of_property_read_reg(np, j, &abs_addr, &size); 79772c350c9STanmay Shah if (ret) { 79872c350c9STanmay Shah dev_err(dev, "failed to get reg property\n"); 79972c350c9STanmay Shah return ret; 80072c350c9STanmay Shah } 80172c350c9STanmay Shah 80272c350c9STanmay Shah /* 80372c350c9STanmay Shah * Remote processor can address only 32 bits 80472c350c9STanmay Shah * so convert 64-bits into 32-bits. This will discard 80572c350c9STanmay Shah * any unwanted upper 32-bits. 80672c350c9STanmay Shah */ 80772c350c9STanmay Shah tcm->da = (u32)abs_addr; 80872c350c9STanmay Shah tcm->size = (u32)size; 80972c350c9STanmay Shah 81072c350c9STanmay Shah cpdev = to_platform_device(dev); 81172c350c9STanmay Shah res = platform_get_resource(cpdev, IORESOURCE_MEM, j); 81272c350c9STanmay Shah if (!res) { 81372c350c9STanmay Shah dev_err(dev, "failed to get tcm resource\n"); 81472c350c9STanmay Shah return -EINVAL; 81572c350c9STanmay Shah } 81672c350c9STanmay Shah 81772c350c9STanmay Shah tcm->addr = (u32)res->start; 81872c350c9STanmay Shah tcm->bank_name = (char *)res->name; 81972c350c9STanmay Shah res = devm_request_mem_region(dev, tcm->addr, tcm->size, 82072c350c9STanmay Shah tcm->bank_name); 82172c350c9STanmay Shah if (!res) { 82272c350c9STanmay Shah dev_err(dev, "failed to request tcm resource\n"); 82372c350c9STanmay Shah return -EINVAL; 82472c350c9STanmay Shah } 82572c350c9STanmay Shah } 82672c350c9STanmay Shah } 82772c350c9STanmay Shah 82872c350c9STanmay Shah return 0; 82972c350c9STanmay Shah } 83072c350c9STanmay Shah 8316b291e80STanmay Shah /** 8326b291e80STanmay Shah * zynqmp_r5_get_tcm_node() 8336b291e80STanmay Shah * Ideally this function should parse tcm node and store information 8346b291e80STanmay Shah * in r5_core instance. For now, Hardcoded TCM information is used. 8356b291e80STanmay Shah * This approach is used as TCM bindings for system-dt is being developed 8366b291e80STanmay Shah * 8376b291e80STanmay Shah * @cluster: pointer to zynqmp_r5_cluster type object 8386b291e80STanmay Shah * 8396b291e80STanmay Shah * Return: 0 for success and < 0 error code for failure. 8406b291e80STanmay Shah */ 8416b291e80STanmay Shah static int zynqmp_r5_get_tcm_node(struct zynqmp_r5_cluster *cluster) 8426b291e80STanmay Shah { 8439af45bbdSTanmay Shah const struct mem_bank_data *zynqmp_tcm_banks; 8446b291e80STanmay Shah struct device *dev = cluster->dev; 8456b291e80STanmay Shah struct zynqmp_r5_core *r5_core; 8466b291e80STanmay Shah int tcm_bank_count, tcm_node; 8476b291e80STanmay Shah int i, j; 8486b291e80STanmay Shah 8499af45bbdSTanmay Shah if (cluster->mode == SPLIT_MODE) { 8509af45bbdSTanmay Shah zynqmp_tcm_banks = zynqmp_tcm_banks_split; 8519af45bbdSTanmay Shah tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks_split); 8529af45bbdSTanmay Shah } else { 8539af45bbdSTanmay Shah zynqmp_tcm_banks = zynqmp_tcm_banks_lockstep; 8549af45bbdSTanmay Shah tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks_lockstep); 8559af45bbdSTanmay Shah } 8566b291e80STanmay Shah 8576b291e80STanmay Shah /* count per core tcm banks */ 8586b291e80STanmay Shah tcm_bank_count = tcm_bank_count / cluster->core_count; 8596b291e80STanmay Shah 8606b291e80STanmay Shah /* 8616b291e80STanmay Shah * r5 core 0 will use all of TCM banks in lockstep mode. 8626b291e80STanmay Shah * In split mode, r5 core0 will use 128k and r5 core1 will use another 8636b291e80STanmay Shah * 128k. Assign TCM banks to each core accordingly 8646b291e80STanmay Shah */ 8656b291e80STanmay Shah tcm_node = 0; 8666b291e80STanmay Shah for (i = 0; i < cluster->core_count; i++) { 8676b291e80STanmay Shah r5_core = cluster->r5_cores[i]; 8686b291e80STanmay Shah r5_core->tcm_banks = devm_kcalloc(dev, tcm_bank_count, 8696b291e80STanmay Shah sizeof(struct mem_bank_data *), 8706b291e80STanmay Shah GFP_KERNEL); 8716b291e80STanmay Shah if (!r5_core->tcm_banks) 8726b291e80STanmay Shah return -ENOMEM; 8736b291e80STanmay Shah 8746b291e80STanmay Shah for (j = 0; j < tcm_bank_count; j++) { 8756b291e80STanmay Shah /* 8766b291e80STanmay Shah * Use pre-defined TCM reg values. 8776b291e80STanmay Shah * Eventually this should be replaced by values 8786b291e80STanmay Shah * parsed from dts. 8796b291e80STanmay Shah */ 8806b291e80STanmay Shah r5_core->tcm_banks[j] = 8816b291e80STanmay Shah (struct mem_bank_data *)&zynqmp_tcm_banks[tcm_node]; 8826b291e80STanmay Shah tcm_node++; 8836b291e80STanmay Shah } 8846b291e80STanmay Shah 8856b291e80STanmay Shah r5_core->tcm_bank_count = tcm_bank_count; 8866b291e80STanmay Shah } 8876b291e80STanmay Shah 8886b291e80STanmay Shah return 0; 8896b291e80STanmay Shah } 8906b291e80STanmay Shah 8916b291e80STanmay Shah /* 8926b291e80STanmay Shah * zynqmp_r5_core_init() 8936b291e80STanmay Shah * Create and initialize zynqmp_r5_core type object 8946b291e80STanmay Shah * 8956b291e80STanmay Shah * @cluster: pointer to zynqmp_r5_cluster type object 8966b291e80STanmay Shah * @fw_reg_val: value expected by firmware to configure RPU cluster mode 8976b291e80STanmay Shah * @tcm_mode: value expected by fw to configure TCM mode (lockstep or split) 8986b291e80STanmay Shah * 8996b291e80STanmay Shah * Return: 0 for success and error code for failure. 9006b291e80STanmay Shah */ 9016b291e80STanmay Shah static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, 9026b291e80STanmay Shah enum rpu_oper_mode fw_reg_val, 9036b291e80STanmay Shah enum rpu_tcm_comb tcm_mode) 9046b291e80STanmay Shah { 9056b291e80STanmay Shah struct device *dev = cluster->dev; 9066b291e80STanmay Shah struct zynqmp_r5_core *r5_core; 907084c2296STanmay Shah int ret = -EINVAL, i; 9086b291e80STanmay Shah 90972c350c9STanmay Shah r5_core = cluster->r5_cores[0]; 91072c350c9STanmay Shah 91172c350c9STanmay Shah /* Maintain backward compatibility for zynqmp by using hardcode TCM address. */ 91272c350c9STanmay Shah if (of_find_property(r5_core->np, "reg", NULL)) 91372c350c9STanmay Shah ret = zynqmp_r5_get_tcm_node_from_dt(cluster); 914a6b974b4STanmay Shah else if (device_is_compatible(dev, "xlnx,zynqmp-r5fss")) 9156b291e80STanmay Shah ret = zynqmp_r5_get_tcm_node(cluster); 91672c350c9STanmay Shah 91772c350c9STanmay Shah if (ret) { 91872c350c9STanmay Shah dev_err(dev, "can't get tcm, err %d\n", ret); 9196b291e80STanmay Shah return ret; 9206b291e80STanmay Shah } 9216b291e80STanmay Shah 9226b291e80STanmay Shah for (i = 0; i < cluster->core_count; i++) { 9236b291e80STanmay Shah r5_core = cluster->r5_cores[i]; 9246b291e80STanmay Shah 9256b291e80STanmay Shah /* Initialize r5 cores with power-domains parsed from dts */ 9266b291e80STanmay Shah ret = of_property_read_u32_index(r5_core->np, "power-domains", 9276b291e80STanmay Shah 1, &r5_core->pm_domain_id); 9286b291e80STanmay Shah if (ret) { 9296b291e80STanmay Shah dev_err(dev, "failed to get power-domains property\n"); 9306b291e80STanmay Shah return ret; 9316b291e80STanmay Shah } 9326b291e80STanmay Shah 933a6b974b4STanmay Shah ret = zynqmp_pm_set_rpu_mode(r5_core->pm_domain_id, fw_reg_val); 934a6b974b4STanmay Shah if (ret < 0) { 935a6b974b4STanmay Shah dev_err(r5_core->dev, "failed to set RPU mode\n"); 9366b291e80STanmay Shah return ret; 9376b291e80STanmay Shah } 938a6b974b4STanmay Shah 939a6b974b4STanmay Shah if (of_find_property(dev_of_node(dev), "xlnx,tcm-mode", NULL) || 940a6b974b4STanmay Shah device_is_compatible(dev, "xlnx,zynqmp-r5fss")) { 941a6b974b4STanmay Shah ret = zynqmp_pm_set_tcm_config(r5_core->pm_domain_id, 942a6b974b4STanmay Shah tcm_mode); 943a6b974b4STanmay Shah if (ret < 0) { 944a6b974b4STanmay Shah dev_err(r5_core->dev, "failed to configure TCM\n"); 945a6b974b4STanmay Shah return ret; 946a6b974b4STanmay Shah } 947a6b974b4STanmay Shah } 9486b291e80STanmay Shah } 9496b291e80STanmay Shah 9506b291e80STanmay Shah return 0; 9516b291e80STanmay Shah } 9526b291e80STanmay Shah 9536b291e80STanmay Shah /* 9546b291e80STanmay Shah * zynqmp_r5_cluster_init() 9556b291e80STanmay Shah * Create and initialize zynqmp_r5_cluster type object 9566b291e80STanmay Shah * 9576b291e80STanmay Shah * @cluster: pointer to zynqmp_r5_cluster type object 9586b291e80STanmay Shah * 9596b291e80STanmay Shah * Return: 0 for success and error code for failure. 9606b291e80STanmay Shah */ 9616b291e80STanmay Shah static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) 9626b291e80STanmay Shah { 9636b291e80STanmay Shah enum zynqmp_r5_cluster_mode cluster_mode = LOCKSTEP_MODE; 9646b291e80STanmay Shah struct device *dev = cluster->dev; 9656b291e80STanmay Shah struct device_node *dev_node = dev_of_node(dev); 9666b291e80STanmay Shah struct platform_device *child_pdev; 9676b291e80STanmay Shah struct zynqmp_r5_core **r5_cores; 9686b291e80STanmay Shah enum rpu_oper_mode fw_reg_val; 9696b291e80STanmay Shah struct device **child_devs; 9706b291e80STanmay Shah struct device_node *child; 9716b291e80STanmay Shah enum rpu_tcm_comb tcm_mode; 9726b291e80STanmay Shah int core_count, ret, i; 9735dfb28c2STanmay Shah struct mbox_info *ipi; 9746b291e80STanmay Shah 9756b291e80STanmay Shah ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode); 9766b291e80STanmay Shah 9776b291e80STanmay Shah /* 9786b291e80STanmay Shah * on success returns 0, if not defined then returns -EINVAL, 9796b291e80STanmay Shah * In that case, default is LOCKSTEP mode. Other than that 9806b291e80STanmay Shah * returns relative error code < 0. 9816b291e80STanmay Shah */ 9826b291e80STanmay Shah if (ret != -EINVAL && ret != 0) { 9836b291e80STanmay Shah dev_err(dev, "Invalid xlnx,cluster-mode property\n"); 9846b291e80STanmay Shah return ret; 9856b291e80STanmay Shah } 9866b291e80STanmay Shah 9876b291e80STanmay Shah /* 9886b291e80STanmay Shah * For now driver only supports split mode and lockstep mode. 9896b291e80STanmay Shah * fail driver probe if either of that is not set in dts. 9906b291e80STanmay Shah */ 9916b291e80STanmay Shah if (cluster_mode == LOCKSTEP_MODE) { 9926b291e80STanmay Shah fw_reg_val = PM_RPU_MODE_LOCKSTEP; 9936b291e80STanmay Shah } else if (cluster_mode == SPLIT_MODE) { 9946b291e80STanmay Shah fw_reg_val = PM_RPU_MODE_SPLIT; 9956b291e80STanmay Shah } else { 9966b291e80STanmay Shah dev_err(dev, "driver does not support cluster mode %d\n", cluster_mode); 9976b291e80STanmay Shah return -EINVAL; 9986b291e80STanmay Shah } 9996b291e80STanmay Shah 100072c350c9STanmay Shah if (of_find_property(dev_node, "xlnx,tcm-mode", NULL)) { 100172c350c9STanmay Shah ret = of_property_read_u32(dev_node, "xlnx,tcm-mode", (u32 *)&tcm_mode); 100272c350c9STanmay Shah if (ret) 100372c350c9STanmay Shah return ret; 1004a6b974b4STanmay Shah } else if (device_is_compatible(dev, "xlnx,zynqmp-r5fss")) { 100572c350c9STanmay Shah if (cluster_mode == LOCKSTEP_MODE) 100672c350c9STanmay Shah tcm_mode = PM_RPU_TCM_COMB; 100772c350c9STanmay Shah else 100872c350c9STanmay Shah tcm_mode = PM_RPU_TCM_SPLIT; 100972c350c9STanmay Shah } 101072c350c9STanmay Shah 10116b291e80STanmay Shah /* 10126b291e80STanmay Shah * Number of cores is decided by number of child nodes of 10136b291e80STanmay Shah * r5f subsystem node in dts. If Split mode is used in dts 10146b291e80STanmay Shah * 2 child nodes are expected. 10156b291e80STanmay Shah * In lockstep mode if two child nodes are available, 10166b291e80STanmay Shah * only use first child node and consider it as core0 10176b291e80STanmay Shah * and ignore core1 dt node. 10186b291e80STanmay Shah */ 10196b291e80STanmay Shah core_count = of_get_available_child_count(dev_node); 10206b291e80STanmay Shah if (core_count == 0) { 10216b291e80STanmay Shah dev_err(dev, "Invalid number of r5 cores %d", core_count); 10226b291e80STanmay Shah return -EINVAL; 10236b291e80STanmay Shah } else if (cluster_mode == SPLIT_MODE && core_count != 2) { 10246b291e80STanmay Shah dev_err(dev, "Invalid number of r5 cores for split mode\n"); 10256b291e80STanmay Shah return -EINVAL; 10266b291e80STanmay Shah } else if (cluster_mode == LOCKSTEP_MODE && core_count == 2) { 10276b291e80STanmay Shah dev_warn(dev, "Only r5 core0 will be used\n"); 10286b291e80STanmay Shah core_count = 1; 10296b291e80STanmay Shah } 10306b291e80STanmay Shah 10316b291e80STanmay Shah child_devs = kcalloc(core_count, sizeof(struct device *), GFP_KERNEL); 10326b291e80STanmay Shah if (!child_devs) 10336b291e80STanmay Shah return -ENOMEM; 10346b291e80STanmay Shah 10356b291e80STanmay Shah r5_cores = kcalloc(core_count, 10366b291e80STanmay Shah sizeof(struct zynqmp_r5_core *), GFP_KERNEL); 10376b291e80STanmay Shah if (!r5_cores) { 10386b291e80STanmay Shah kfree(child_devs); 10396b291e80STanmay Shah return -ENOMEM; 10406b291e80STanmay Shah } 10416b291e80STanmay Shah 10426b291e80STanmay Shah i = 0; 10436b291e80STanmay Shah for_each_available_child_of_node(dev_node, child) { 10446b291e80STanmay Shah child_pdev = of_find_device_by_node(child); 10456b291e80STanmay Shah if (!child_pdev) { 10466b291e80STanmay Shah of_node_put(child); 10476b291e80STanmay Shah ret = -ENODEV; 10486b291e80STanmay Shah goto release_r5_cores; 10496b291e80STanmay Shah } 10506b291e80STanmay Shah 10516b291e80STanmay Shah child_devs[i] = &child_pdev->dev; 10526b291e80STanmay Shah 10536b291e80STanmay Shah /* create and add remoteproc instance of type struct rproc */ 10546b291e80STanmay Shah r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev); 10556b291e80STanmay Shah if (IS_ERR(r5_cores[i])) { 10566b291e80STanmay Shah of_node_put(child); 10576b291e80STanmay Shah ret = PTR_ERR(r5_cores[i]); 10586b291e80STanmay Shah r5_cores[i] = NULL; 10596b291e80STanmay Shah goto release_r5_cores; 10606b291e80STanmay Shah } 10616b291e80STanmay Shah 10626b291e80STanmay Shah /* 10635dfb28c2STanmay Shah * If mailbox nodes are disabled using "status" property then 10645dfb28c2STanmay Shah * setting up mailbox channels will fail. 10655dfb28c2STanmay Shah */ 10665dfb28c2STanmay Shah ipi = zynqmp_r5_setup_mbox(&child_pdev->dev); 10675dfb28c2STanmay Shah if (ipi) { 10685dfb28c2STanmay Shah r5_cores[i]->ipi = ipi; 10695dfb28c2STanmay Shah ipi->r5_core = r5_cores[i]; 10705dfb28c2STanmay Shah } 10715dfb28c2STanmay Shah 10725dfb28c2STanmay Shah /* 10736b291e80STanmay Shah * If two child nodes are available in dts in lockstep mode, 10746b291e80STanmay Shah * then ignore second child node. 10756b291e80STanmay Shah */ 10766b291e80STanmay Shah if (cluster_mode == LOCKSTEP_MODE) { 10776b291e80STanmay Shah of_node_put(child); 10786b291e80STanmay Shah break; 10796b291e80STanmay Shah } 10806b291e80STanmay Shah 10816b291e80STanmay Shah i++; 10826b291e80STanmay Shah } 10836b291e80STanmay Shah 10846b291e80STanmay Shah cluster->mode = cluster_mode; 10856b291e80STanmay Shah cluster->core_count = core_count; 10866b291e80STanmay Shah cluster->r5_cores = r5_cores; 10876b291e80STanmay Shah 10886b291e80STanmay Shah ret = zynqmp_r5_core_init(cluster, fw_reg_val, tcm_mode); 10896b291e80STanmay Shah if (ret < 0) { 10906b291e80STanmay Shah dev_err(dev, "failed to init r5 core err %d\n", ret); 10916b291e80STanmay Shah cluster->core_count = 0; 10926b291e80STanmay Shah cluster->r5_cores = NULL; 10936b291e80STanmay Shah 10946b291e80STanmay Shah /* 10956b291e80STanmay Shah * at this point rproc resources for each core are allocated. 10966b291e80STanmay Shah * adjust index to free resources in reverse order 10976b291e80STanmay Shah */ 10986b291e80STanmay Shah i = core_count - 1; 10996b291e80STanmay Shah goto release_r5_cores; 11006b291e80STanmay Shah } 11016b291e80STanmay Shah 11026b291e80STanmay Shah kfree(child_devs); 11036b291e80STanmay Shah return 0; 11046b291e80STanmay Shah 11056b291e80STanmay Shah release_r5_cores: 11066b291e80STanmay Shah while (i >= 0) { 11076b291e80STanmay Shah put_device(child_devs[i]); 11086b291e80STanmay Shah if (r5_cores[i]) { 11095dfb28c2STanmay Shah zynqmp_r5_free_mbox(r5_cores[i]->ipi); 11106b291e80STanmay Shah of_reserved_mem_device_release(r5_cores[i]->dev); 11116b291e80STanmay Shah rproc_del(r5_cores[i]->rproc); 11126b291e80STanmay Shah rproc_free(r5_cores[i]->rproc); 11136b291e80STanmay Shah } 11146b291e80STanmay Shah i--; 11156b291e80STanmay Shah } 11166b291e80STanmay Shah kfree(r5_cores); 11176b291e80STanmay Shah kfree(child_devs); 11186b291e80STanmay Shah return ret; 11196b291e80STanmay Shah } 11206b291e80STanmay Shah 11216b291e80STanmay Shah static void zynqmp_r5_cluster_exit(void *data) 11226b291e80STanmay Shah { 112386660713SYu Zhe struct platform_device *pdev = data; 11246b291e80STanmay Shah struct zynqmp_r5_cluster *cluster; 11256b291e80STanmay Shah struct zynqmp_r5_core *r5_core; 11266b291e80STanmay Shah int i; 11276b291e80STanmay Shah 112886660713SYu Zhe cluster = platform_get_drvdata(pdev); 11296b291e80STanmay Shah if (!cluster) 11306b291e80STanmay Shah return; 11316b291e80STanmay Shah 11326b291e80STanmay Shah for (i = 0; i < cluster->core_count; i++) { 11336b291e80STanmay Shah r5_core = cluster->r5_cores[i]; 11345dfb28c2STanmay Shah zynqmp_r5_free_mbox(r5_core->ipi); 11356b291e80STanmay Shah of_reserved_mem_device_release(r5_core->dev); 11366b291e80STanmay Shah put_device(r5_core->dev); 11376b291e80STanmay Shah rproc_del(r5_core->rproc); 11386b291e80STanmay Shah rproc_free(r5_core->rproc); 11396b291e80STanmay Shah } 11406b291e80STanmay Shah 11416b291e80STanmay Shah kfree(cluster->r5_cores); 11426b291e80STanmay Shah kfree(cluster); 11436b291e80STanmay Shah platform_set_drvdata(pdev, NULL); 11446b291e80STanmay Shah } 11456b291e80STanmay Shah 11466b291e80STanmay Shah /* 11476b291e80STanmay Shah * zynqmp_r5_remoteproc_probe() 11486b291e80STanmay Shah * parse device-tree, initialize hardware and allocate required resources 11496b291e80STanmay Shah * and remoteproc ops 11506b291e80STanmay Shah * 11516b291e80STanmay Shah * @pdev: domain platform device for R5 cluster 11526b291e80STanmay Shah * 11536b291e80STanmay Shah * Return: 0 for success and < 0 for failure. 11546b291e80STanmay Shah */ 11556b291e80STanmay Shah static int zynqmp_r5_remoteproc_probe(struct platform_device *pdev) 11566b291e80STanmay Shah { 11576b291e80STanmay Shah struct zynqmp_r5_cluster *cluster; 11586b291e80STanmay Shah struct device *dev = &pdev->dev; 11596b291e80STanmay Shah int ret; 11606b291e80STanmay Shah 11616b291e80STanmay Shah cluster = kzalloc(sizeof(*cluster), GFP_KERNEL); 11626b291e80STanmay Shah if (!cluster) 11636b291e80STanmay Shah return -ENOMEM; 11646b291e80STanmay Shah 11656b291e80STanmay Shah cluster->dev = dev; 11666b291e80STanmay Shah 11676b291e80STanmay Shah ret = devm_of_platform_populate(dev); 11686b291e80STanmay Shah if (ret) { 11696b291e80STanmay Shah dev_err_probe(dev, ret, "failed to populate platform dev\n"); 11706b291e80STanmay Shah kfree(cluster); 11716b291e80STanmay Shah return ret; 11726b291e80STanmay Shah } 11736b291e80STanmay Shah 11746b291e80STanmay Shah /* wire in so each core can be cleaned up at driver remove */ 11756b291e80STanmay Shah platform_set_drvdata(pdev, cluster); 11766b291e80STanmay Shah 11776b291e80STanmay Shah ret = zynqmp_r5_cluster_init(cluster); 11786b291e80STanmay Shah if (ret) { 11796b291e80STanmay Shah kfree(cluster); 11806b291e80STanmay Shah platform_set_drvdata(pdev, NULL); 11816b291e80STanmay Shah dev_err_probe(dev, ret, "Invalid r5f subsystem device tree\n"); 11826b291e80STanmay Shah return ret; 11836b291e80STanmay Shah } 11846b291e80STanmay Shah 11856b291e80STanmay Shah ret = devm_add_action_or_reset(dev, zynqmp_r5_cluster_exit, pdev); 11866b291e80STanmay Shah if (ret) 11876b291e80STanmay Shah return ret; 11886b291e80STanmay Shah 11896b291e80STanmay Shah return 0; 11906b291e80STanmay Shah } 11916b291e80STanmay Shah 11926b291e80STanmay Shah /* Match table for OF platform binding */ 11936b291e80STanmay Shah static const struct of_device_id zynqmp_r5_remoteproc_match[] = { 1194a6b974b4STanmay Shah { .compatible = "xlnx,versal-net-r52fss", }, 1195a6b974b4STanmay Shah { .compatible = "xlnx,versal-r5fss", }, 11966b291e80STanmay Shah { .compatible = "xlnx,zynqmp-r5fss", }, 11976b291e80STanmay Shah { /* end of list */ }, 11986b291e80STanmay Shah }; 11996b291e80STanmay Shah MODULE_DEVICE_TABLE(of, zynqmp_r5_remoteproc_match); 12006b291e80STanmay Shah 12016b291e80STanmay Shah static struct platform_driver zynqmp_r5_remoteproc_driver = { 12026b291e80STanmay Shah .probe = zynqmp_r5_remoteproc_probe, 12036b291e80STanmay Shah .driver = { 12046b291e80STanmay Shah .name = "zynqmp_r5_remoteproc", 12056b291e80STanmay Shah .of_match_table = zynqmp_r5_remoteproc_match, 12066b291e80STanmay Shah }, 12076b291e80STanmay Shah }; 12086b291e80STanmay Shah module_platform_driver(zynqmp_r5_remoteproc_driver); 12096b291e80STanmay Shah 12106b291e80STanmay Shah MODULE_DESCRIPTION("Xilinx R5F remote processor driver"); 12116b291e80STanmay Shah MODULE_AUTHOR("Xilinx Inc."); 12126b291e80STanmay Shah MODULE_LICENSE("GPL"); 1213