1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Renesas R-Car MFIS (Multifunctional Interface) driver 4 * 5 * Copyright (C) Renesas Solutions Corp. 6 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7 * Wolfram Sang <wsa+renesas@sang-engineering.com> 8 */ 9 #include <dt-bindings/soc/renesas,r8a78000-mfis.h> 10 #include <linux/device.h> 11 #include <linux/interrupt.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/mailbox_controller.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/of_irq.h> 18 #include <linux/of_platform.h> 19 #include <linux/platform_device.h> 20 #include <linux/spinlock.h> 21 22 #define MFISWPCNTR 0x0900 23 #define MFISWACNTR 0x0904 24 25 #define MFIS_X5H_IICR(i) ((i) * 0x1000 + 0x00) 26 #define MFIS_X5H_EICR(i) ((i) * 0x1000 + 0x04) 27 28 #define MFIS_UNPROTECT_KEY 0xACCE0000 29 30 struct mfis_priv; 31 32 struct mfis_reg { 33 void __iomem *base; 34 resource_size_t start; 35 struct mfis_priv *priv; 36 }; 37 38 struct mfis_info { 39 u32 unprotect_mask; 40 unsigned int mb_num_channels; 41 unsigned int mb_reg_comes_from_dt:1; 42 unsigned int mb_tx_uses_eicr:1; 43 unsigned int mb_channels_are_unidir:1; 44 u32 (*mb_calc_reg)(u32 chan_num, bool tx_uses_eicr, bool is_only_rx); 45 }; 46 47 struct mfis_chan_priv { 48 u32 reg; 49 int irq; 50 }; 51 52 struct mfis_priv { 53 spinlock_t unprotect_lock; /* guards access to the unprotection reg */ 54 struct device *dev; 55 struct mfis_reg common_reg; 56 struct mfis_reg mbox_reg; 57 const struct mfis_info *info; 58 59 /* mailbox private data */ 60 struct mbox_controller mbox; 61 struct mfis_chan_priv *chan_privs; 62 }; 63 64 static u32 mfis_read(struct mfis_reg *mreg, unsigned int reg) 65 { 66 return ioread32(mreg->base + reg); 67 } 68 69 static void mfis_write(struct mfis_reg *mreg, u32 reg, u32 val) 70 { 71 struct mfis_priv *priv = mreg->priv; 72 u32 unprotect_mask = priv->info->unprotect_mask; 73 unsigned long flags; 74 u32 unprotect_code; 75 76 /* 77 * [Gen4] key: 0xACCE0000, mask: 0x0000FFFF 78 * [Gen5] key: 0xACC00000, mask: 0x000FFFFF 79 */ 80 unprotect_code = (MFIS_UNPROTECT_KEY & ~unprotect_mask) | 81 ((mreg->start + reg) & unprotect_mask); 82 83 spin_lock_irqsave(&priv->unprotect_lock, flags); 84 iowrite32(unprotect_code, priv->common_reg.base + MFISWACNTR); 85 iowrite32(val, mreg->base + reg); 86 spin_unlock_irqrestore(&priv->unprotect_lock, flags); 87 } 88 89 /******************************************************** 90 * Mailbox * 91 ********************************************************/ 92 93 #define mfis_mb_mbox_to_priv(_m) container_of((_m), struct mfis_priv, mbox) 94 95 static irqreturn_t mfis_mb_iicr_interrupt(int irq, void *data) 96 { 97 struct mbox_chan *chan = data; 98 struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox); 99 struct mfis_chan_priv *chan_priv = chan->con_priv; 100 101 mbox_chan_received_data(chan, NULL); 102 /* Stop remote(!) doorbell */ 103 mfis_write(&priv->mbox_reg, chan_priv->reg, 0); 104 105 return IRQ_HANDLED; 106 } 107 108 static int mfis_mb_startup(struct mbox_chan *chan) 109 { 110 struct mfis_chan_priv *chan_priv = chan->con_priv; 111 112 if (!chan_priv->irq) 113 return 0; 114 115 return request_irq(chan_priv->irq, mfis_mb_iicr_interrupt, 0, 116 dev_name(chan->mbox->dev), chan); 117 } 118 119 static void mfis_mb_shutdown(struct mbox_chan *chan) 120 { 121 struct mfis_chan_priv *chan_priv = chan->con_priv; 122 123 if (chan_priv->irq) 124 free_irq(chan_priv->irq, chan); 125 } 126 127 static int mfis_mb_iicr_send_data(struct mbox_chan *chan, void *data) 128 { 129 struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox); 130 struct mfis_chan_priv *chan_priv = chan->con_priv; 131 132 /* Our doorbell still active? */ 133 if (mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0)) 134 return -EBUSY; 135 136 /* Start our doorbell */ 137 mfis_write(&priv->mbox_reg, chan_priv->reg, BIT(0)); 138 139 return 0; 140 } 141 142 static bool mfis_mb_iicr_last_tx_done(struct mbox_chan *chan) 143 { 144 struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox); 145 struct mfis_chan_priv *chan_priv = chan->con_priv; 146 147 /* Our doorbell still active? */ 148 return !(mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0)); 149 } 150 151 /* For MFIS variants using the IICR/EICR register pair */ 152 static const struct mbox_chan_ops mfis_iicr_ops = { 153 .startup = mfis_mb_startup, 154 .shutdown = mfis_mb_shutdown, 155 .send_data = mfis_mb_iicr_send_data, 156 .last_tx_done = mfis_mb_iicr_last_tx_done, 157 }; 158 159 static u32 mfis_mb_r8a779g0_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx) 160 { 161 unsigned int i, k; 162 u32 reg; 163 164 i = chan_num & 3; 165 k = chan_num >> 2; 166 167 if (is_only_rx) { 168 if (k < 2) 169 reg = 0x9404 + 0x1020 * k + 0x08 * i; 170 else 171 reg = 0xb504 + 0x08 * i; 172 } else { 173 if (k < 2) 174 reg = 0x1400 + 0x1008 * i + 0x20 * k; 175 else 176 reg = 0x1500 + 0x1008 * i; 177 } 178 179 return reg; 180 } 181 182 static u32 mfis_mb_r8a78000_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx) 183 { 184 return (tx_uses_eicr ^ is_only_rx) ? MFIS_X5H_EICR(chan_num) : 185 MFIS_X5H_IICR(chan_num); 186 } 187 188 static struct mbox_chan *mfis_mb_of_xlate(struct mbox_controller *mbox, 189 const struct of_phandle_args *sp) 190 { 191 struct mfis_priv *priv = mfis_mb_mbox_to_priv(mbox); 192 struct mfis_chan_priv *chan_priv; 193 bool tx_uses_eicr, is_only_rx; 194 u32 chan_num, chan_flags; 195 struct mbox_chan *chan; 196 197 if (sp->args_count != 2) 198 return ERR_PTR(-EINVAL); 199 200 chan_num = sp->args[0]; 201 chan_flags = sp->args[1]; 202 203 if (chan_num >= priv->info->mb_num_channels) 204 return ERR_PTR(-EINVAL); 205 206 /* Channel layout is described in mfis_mb_probe() */ 207 if (priv->info->mb_channels_are_unidir) { 208 is_only_rx = chan_flags & MFIS_CHANNEL_RX; 209 chan = mbox->chans + 2 * chan_num + is_only_rx; 210 } else { 211 is_only_rx = false; 212 chan = mbox->chans + chan_num; 213 } 214 215 if (priv->info->mb_reg_comes_from_dt) { 216 tx_uses_eicr = chan_flags & MFIS_CHANNEL_EICR; 217 if (tx_uses_eicr) 218 chan += mbox->num_chans / 2; 219 } else { 220 tx_uses_eicr = priv->info->mb_tx_uses_eicr; 221 } 222 223 chan_priv = chan->con_priv; 224 chan_priv->reg = priv->info->mb_calc_reg(chan_num, tx_uses_eicr, is_only_rx); 225 226 if (!priv->info->mb_channels_are_unidir || is_only_rx) { 227 char irqname[8]; 228 char suffix = tx_uses_eicr ? 'i' : 'e'; 229 230 /* "ch0i" or "ch0e" */ 231 scnprintf(irqname, sizeof(irqname), "ch%u%c", chan_num, suffix); 232 233 chan_priv->irq = of_irq_get_byname(mbox->dev->of_node, irqname); 234 if (chan_priv->irq < 0) 235 return ERR_PTR(chan_priv->irq); 236 if (chan_priv->irq == 0) 237 return ERR_PTR(-ENOENT); 238 } 239 240 return chan; 241 } 242 243 static int mfis_mb_probe(struct mfis_priv *priv) 244 { 245 unsigned int num_chan = priv->info->mb_num_channels; 246 struct device *dev = priv->dev; 247 struct mbox_controller *mbox; 248 struct mbox_chan *chan; 249 250 if (priv->info->mb_channels_are_unidir) { 251 /* Channel layout: Ch0-TX, Ch0-RX, Ch1-TX... */ 252 num_chan *= 2; 253 } 254 255 if (priv->info->mb_reg_comes_from_dt) { 256 /* Channel layout: <n> IICR channels, <n> EICR channels */ 257 num_chan *= 2; 258 } 259 260 chan = devm_kcalloc(dev, num_chan, sizeof(*chan), GFP_KERNEL); 261 if (!chan) 262 return -ENOMEM; 263 264 priv->chan_privs = devm_kcalloc(dev, num_chan, sizeof(*priv->chan_privs), 265 GFP_KERNEL); 266 if (!priv->chan_privs) 267 return -ENOMEM; 268 269 mbox = &priv->mbox; 270 271 for (unsigned int i = 0; i < num_chan; i++) 272 chan[i].con_priv = &priv->chan_privs[i]; 273 274 mbox->chans = chan; 275 mbox->num_chans = num_chan; 276 mbox->txdone_poll = true; 277 mbox->ops = &mfis_iicr_ops; 278 mbox->dev = dev; 279 mbox->of_xlate = mfis_mb_of_xlate; 280 281 return devm_mbox_controller_register(dev, mbox); 282 } 283 284 /******************************************************** 285 * Common * 286 ********************************************************/ 287 static int mfis_reg_probe(struct platform_device *pdev, struct mfis_priv *priv, 288 struct mfis_reg *mreg, const char *name, bool required) 289 { 290 struct resource *res; 291 void __iomem *base; 292 293 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 294 295 /* If there is no mailbox resource, registers are in the common space */ 296 if (!res && !required) { 297 *mreg = priv->common_reg; 298 } else { 299 base = devm_ioremap_resource(&pdev->dev, res); 300 if (IS_ERR(base)) 301 return PTR_ERR(base); 302 303 mreg->base = base; 304 mreg->start = res->start; 305 mreg->priv = priv; 306 } 307 308 return 0; 309 } 310 311 static int mfis_probe(struct platform_device *pdev) 312 { 313 struct device *dev = &pdev->dev; 314 struct mfis_priv *priv; 315 int ret; 316 317 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 318 if (!priv) 319 return -ENOMEM; 320 321 priv->dev = dev; 322 priv->info = of_device_get_match_data(dev); 323 if (!priv->info) 324 return -ENOENT; 325 326 spin_lock_init(&priv->unprotect_lock); 327 328 ret = mfis_reg_probe(pdev, priv, &priv->common_reg, "common", true); 329 if (ret) 330 return ret; 331 332 ret = mfis_reg_probe(pdev, priv, &priv->mbox_reg, "mboxes", false); 333 if (ret) 334 return ret; 335 336 return mfis_mb_probe(priv); 337 } 338 339 static const struct mfis_info mfis_info_r8a779g0 = { 340 .unprotect_mask = 0x0000ffff, 341 .mb_num_channels = 12, 342 .mb_channels_are_unidir = true, 343 .mb_calc_reg = mfis_mb_r8a779g0_calc_reg, 344 }; 345 346 static const struct mfis_info mfis_info_r8a78000 = { 347 .unprotect_mask = 0x000fffff, 348 .mb_num_channels = 64, 349 .mb_reg_comes_from_dt = true, 350 .mb_channels_are_unidir = true, 351 .mb_calc_reg = mfis_mb_r8a78000_calc_reg, 352 }; 353 354 static const struct mfis_info mfis_info_r8a78000_scp = { 355 .unprotect_mask = 0x000fffff, 356 .mb_num_channels = 32, 357 .mb_tx_uses_eicr = true, 358 .mb_channels_are_unidir = true, 359 .mb_calc_reg = mfis_mb_r8a78000_calc_reg, 360 }; 361 362 static const struct of_device_id mfis_mfd_of_match[] = { 363 { .compatible = "renesas,r8a779g0-mfis", .data = &mfis_info_r8a779g0, }, 364 { .compatible = "renesas,r8a779h0-mfis", .data = &mfis_info_r8a779g0, }, 365 { .compatible = "renesas,r8a78000-mfis", .data = &mfis_info_r8a78000, }, 366 { .compatible = "renesas,r8a78000-mfis-scp", .data = &mfis_info_r8a78000_scp, }, 367 {} 368 }; 369 MODULE_DEVICE_TABLE(of, mfis_mfd_of_match); 370 371 static struct platform_driver mfis_driver = { 372 .driver = { 373 .name = "rcar-mfis", 374 .of_match_table = mfis_mfd_of_match, 375 .suppress_bind_attrs = true, 376 }, 377 .probe = mfis_probe, 378 }; 379 module_platform_driver(mfis_driver); 380 381 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 382 MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>"); 383 MODULE_LICENSE("GPL"); 384 MODULE_DESCRIPTION("Renesas R-Car MFIS driver"); 385