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