1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Microchip PolarFire SoC (MPFS) system controller/mailbox controller driver 4 * 5 * Copyright (c) 2020-2022 Microchip Corporation. All rights reserved. 6 * 7 * Author: Conor Dooley <conor.dooley@microchip.com> 8 * 9 */ 10 11 #include <linux/io.h> 12 #include <linux/err.h> 13 #include <linux/init.h> 14 #include <linux/module.h> 15 #include <linux/kernel.h> 16 #include <linux/interrupt.h> 17 #include <linux/platform_device.h> 18 #include <linux/mailbox_controller.h> 19 #include <soc/microchip/mpfs.h> 20 21 #define SERVICES_CR_OFFSET 0x50u 22 #define SERVICES_SR_OFFSET 0x54u 23 #define MAILBOX_REG_OFFSET 0x800u 24 #define MSS_SYS_MAILBOX_DATA_OFFSET 0u 25 #define SCB_MASK_WIDTH 16u 26 27 /* SCBCTRL service control register */ 28 29 #define SCB_CTRL_REQ (0) 30 #define SCB_CTRL_REQ_MASK BIT(SCB_CTRL_REQ) 31 32 #define SCB_CTRL_BUSY (1) 33 #define SCB_CTRL_BUSY_MASK BIT(SCB_CTRL_BUSY) 34 35 #define SCB_CTRL_ABORT (2) 36 #define SCB_CTRL_ABORT_MASK BIT(SCB_CTRL_ABORT) 37 38 #define SCB_CTRL_NOTIFY (3) 39 #define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY) 40 41 #define SCB_CTRL_POS (16) 42 #define SCB_CTRL_MASK GENMASK_ULL(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS) 43 44 /* SCBCTRL service status register */ 45 46 #define SCB_STATUS_REQ (0) 47 #define SCB_STATUS_REQ_MASK BIT(SCB_STATUS_REQ) 48 49 #define SCB_STATUS_BUSY (1) 50 #define SCB_STATUS_BUSY_MASK BIT(SCB_STATUS_BUSY) 51 52 #define SCB_STATUS_ABORT (2) 53 #define SCB_STATUS_ABORT_MASK BIT(SCB_STATUS_ABORT) 54 55 #define SCB_STATUS_NOTIFY (3) 56 #define SCB_STATUS_NOTIFY_MASK BIT(SCB_STATUS_NOTIFY) 57 58 #define SCB_STATUS_POS (16) 59 #define SCB_STATUS_MASK GENMASK(SCB_STATUS_POS + SCB_MASK_WIDTH - 1, SCB_STATUS_POS) 60 61 struct mpfs_mbox { 62 struct mbox_controller controller; 63 struct device *dev; 64 int irq; 65 void __iomem *ctrl_base; 66 void __iomem *mbox_base; 67 void __iomem *int_reg; 68 struct mbox_chan chans[1]; 69 struct mpfs_mss_response *response; 70 u16 resp_offset; 71 }; 72 73 static bool mpfs_mbox_busy(struct mpfs_mbox *mbox) 74 { 75 u32 status; 76 77 status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); 78 79 return status & SCB_STATUS_BUSY_MASK; 80 } 81 82 static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data) 83 { 84 struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; 85 struct mpfs_mss_msg *msg = data; 86 u32 tx_trigger; 87 u16 opt_sel; 88 u32 val = 0u; 89 90 mbox->response = msg->response; 91 mbox->resp_offset = msg->resp_offset; 92 93 if (mpfs_mbox_busy(mbox)) 94 return -EBUSY; 95 96 if (msg->cmd_data_size) { 97 u32 index; 98 u8 extra_bits = msg->cmd_data_size & 3; 99 u32 *word_buf = (u32 *)msg->cmd_data; 100 101 for (index = 0; index < (msg->cmd_data_size / 4); index++) 102 writel_relaxed(word_buf[index], 103 mbox->mbox_base + msg->mbox_offset + index * 0x4); 104 if (extra_bits) { 105 u8 i; 106 u8 byte_off = ALIGN_DOWN(msg->cmd_data_size, 4); 107 u8 *byte_buf = msg->cmd_data + byte_off; 108 109 val = readl_relaxed(mbox->mbox_base + msg->mbox_offset + index * 0x4); 110 111 for (i = 0u; i < extra_bits; i++) { 112 val &= ~(0xffu << (i * 8u)); 113 val |= (byte_buf[i] << (i * 8u)); 114 } 115 116 writel_relaxed(val, mbox->mbox_base + msg->mbox_offset + index * 0x4); 117 } 118 } 119 120 opt_sel = ((msg->mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu)); 121 tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK; 122 tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK; 123 writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET); 124 125 return 0; 126 } 127 128 static void mpfs_mbox_rx_data(struct mbox_chan *chan) 129 { 130 struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; 131 struct mpfs_mss_response *response = mbox->response; 132 u16 num_words = ALIGN((response->resp_size), (4)) / 4U; 133 u32 i, status; 134 135 if (!response->resp_msg) { 136 dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM); 137 return; 138 } 139 140 /* 141 * The status is stored in bits 31:16 of the SERVICES_SR register. 142 * It is only valid when BUSY == 0. 143 * We should *never* get an interrupt while the controller is 144 * still in the busy state. If we do, something has gone badly 145 * wrong & the content of the mailbox would not be valid. 146 */ 147 if (mpfs_mbox_busy(mbox)) { 148 dev_err(mbox->dev, "got an interrupt but system controller is busy\n"); 149 response->resp_status = 0xDEAD; 150 return; 151 } 152 153 status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); 154 155 /* 156 * If the status of the individual servers is non-zero, the service has 157 * failed. The contents of the mailbox at this point are not be valid, 158 * so don't bother reading them. Set the status so that the driver 159 * implementing the service can handle the result. 160 */ 161 response->resp_status = (status & SCB_STATUS_MASK) >> SCB_STATUS_POS; 162 if (response->resp_status) 163 return; 164 165 if (!mpfs_mbox_busy(mbox)) { 166 for (i = 0; i < num_words; i++) { 167 response->resp_msg[i] = 168 readl_relaxed(mbox->mbox_base 169 + mbox->resp_offset + i * 0x4); 170 } 171 } 172 173 mbox_chan_received_data(chan, response); 174 } 175 176 static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data) 177 { 178 struct mbox_chan *chan = data; 179 struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; 180 181 writel_relaxed(0, mbox->int_reg); 182 183 mpfs_mbox_rx_data(chan); 184 185 mbox_chan_txdone(chan, 0); 186 return IRQ_HANDLED; 187 } 188 189 static int mpfs_mbox_startup(struct mbox_chan *chan) 190 { 191 struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; 192 int ret = 0; 193 194 if (!mbox) 195 return -EINVAL; 196 197 ret = devm_request_irq(mbox->dev, mbox->irq, mpfs_mbox_inbox_isr, 0, "mpfs-mailbox", chan); 198 if (ret) 199 dev_err(mbox->dev, "failed to register mailbox interrupt:%d\n", ret); 200 201 return ret; 202 } 203 204 static void mpfs_mbox_shutdown(struct mbox_chan *chan) 205 { 206 struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; 207 208 devm_free_irq(mbox->dev, mbox->irq, chan); 209 } 210 211 static const struct mbox_chan_ops mpfs_mbox_ops = { 212 .send_data = mpfs_mbox_send_data, 213 .startup = mpfs_mbox_startup, 214 .shutdown = mpfs_mbox_shutdown, 215 }; 216 217 static int mpfs_mbox_probe(struct platform_device *pdev) 218 { 219 struct mpfs_mbox *mbox; 220 struct resource *regs; 221 int ret; 222 223 mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL); 224 if (!mbox) 225 return -ENOMEM; 226 227 mbox->ctrl_base = devm_platform_get_and_ioremap_resource(pdev, 0, ®s); 228 if (IS_ERR(mbox->ctrl_base)) 229 return PTR_ERR(mbox->ctrl_base); 230 231 mbox->int_reg = devm_platform_get_and_ioremap_resource(pdev, 1, ®s); 232 if (IS_ERR(mbox->int_reg)) 233 return PTR_ERR(mbox->int_reg); 234 235 mbox->mbox_base = devm_platform_get_and_ioremap_resource(pdev, 2, ®s); 236 if (IS_ERR(mbox->mbox_base)) // account for the old dt-binding w/ 2 regs 237 mbox->mbox_base = mbox->ctrl_base + MAILBOX_REG_OFFSET; 238 239 mbox->irq = platform_get_irq(pdev, 0); 240 if (mbox->irq < 0) 241 return mbox->irq; 242 243 mbox->dev = &pdev->dev; 244 245 mbox->chans[0].con_priv = mbox; 246 mbox->controller.dev = mbox->dev; 247 mbox->controller.num_chans = 1; 248 mbox->controller.chans = mbox->chans; 249 mbox->controller.ops = &mpfs_mbox_ops; 250 mbox->controller.txdone_irq = true; 251 252 ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller); 253 if (ret) { 254 dev_err(&pdev->dev, "Registering MPFS mailbox controller failed\n"); 255 return ret; 256 } 257 dev_info(&pdev->dev, "Registered MPFS mailbox controller driver\n"); 258 259 return 0; 260 } 261 262 static const struct of_device_id mpfs_mbox_of_match[] = { 263 {.compatible = "microchip,mpfs-mailbox", }, 264 {}, 265 }; 266 MODULE_DEVICE_TABLE(of, mpfs_mbox_of_match); 267 268 static struct platform_driver mpfs_mbox_driver = { 269 .driver = { 270 .name = "mpfs-mailbox", 271 .of_match_table = mpfs_mbox_of_match, 272 }, 273 .probe = mpfs_mbox_probe, 274 }; 275 module_platform_driver(mpfs_mbox_driver); 276 277 MODULE_LICENSE("GPL v2"); 278 MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>"); 279 MODULE_DESCRIPTION("MPFS mailbox controller driver"); 280