1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2020 Samsung Electronics Co., Ltd. 4 * Copyright 2020 Google LLC. 5 * Copyright 2024 Linaro Ltd. 6 */ 7 8 #include <linux/bitops.h> 9 #include <linux/bits.h> 10 #include <linux/clk.h> 11 #include <linux/io.h> 12 #include <linux/mailbox_controller.h> 13 #include <linux/mailbox/exynos-message.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/platform_device.h> 17 #include <linux/slab.h> 18 19 #define EXYNOS_MBOX_INTMR0 0x28 /* Interrupt Mask Register 0 */ 20 #define EXYNOS_MBOX_INTGR1 0x40 /* Interrupt Generation Register 1 */ 21 22 #define EXYNOS_MBOX_INTMR0_MASK GENMASK(15, 0) 23 #define EXYNOS_MBOX_INTGR1_MASK GENMASK(15, 0) 24 25 #define EXYNOS_MBOX_CHAN_COUNT HWEIGHT32(EXYNOS_MBOX_INTGR1_MASK) 26 27 #define EXYNOS850_MBOX_INTGR0 0x8 /* Interrupt Generation Register 0 */ 28 #define EXYNOS850_MBOX_INTMR1 0x24 /* Interrupt Mask Register 1 */ 29 30 #define EXYNOS850_MBOX_INTMR1_MASK GENMASK(15, 0) 31 #define EXYNOS850_MBOX_INTGR0_MASK GENMASK(31, 16) 32 33 #define EXYNOS850_MBOX_CHAN_COUNT HWEIGHT32(EXYNOS850_MBOX_INTGR0_MASK) 34 35 /** 36 * struct exynos_mbox_driver_data - platform-specific mailbox configuration. 37 * @intgr: offset to the IRQ generation register, doorbell 38 * to APM co-processor. 39 * @intgr_shift: shift to apply to the value written to IRQ generation 40 * register. 41 * @intmr: offset to the IRQ mask register. 42 * @intmr_mask: value to write to the mask register to mask out all 43 * interrupts. 44 * @num_chans: number of channels the mailbox can support (hardware 45 * capability). 46 */ 47 struct exynos_mbox_driver_data { 48 u32 intgr; 49 u32 intgr_shift; 50 u32 intmr; 51 u32 intmr_mask; 52 int num_chans; 53 }; 54 55 /** 56 * struct exynos_mbox - driver's private data. 57 * @regs: mailbox registers base address. 58 * @mbox: pointer to the mailbox controller. 59 * @data: pointer to driver platform-specific data. 60 */ 61 struct exynos_mbox { 62 void __iomem *regs; 63 struct mbox_controller *mbox; 64 const struct exynos_mbox_driver_data *data; 65 }; 66 67 static const struct exynos_mbox_driver_data exynos850_mbox_data = { 68 .intgr = EXYNOS850_MBOX_INTGR0, 69 .intgr_shift = 16, 70 .intmr = EXYNOS850_MBOX_INTMR1, 71 .intmr_mask = EXYNOS850_MBOX_INTMR1_MASK, 72 .num_chans = EXYNOS850_MBOX_CHAN_COUNT, 73 }; 74 75 static const struct exynos_mbox_driver_data exynos_gs101_mbox_data = { 76 .intgr = EXYNOS_MBOX_INTGR1, 77 .intgr_shift = 0, 78 .intmr = EXYNOS_MBOX_INTMR0, 79 .intmr_mask = EXYNOS_MBOX_INTMR0_MASK, 80 .num_chans = EXYNOS_MBOX_CHAN_COUNT, 81 }; 82 83 static int exynos_mbox_send_data(struct mbox_chan *chan, void *data) 84 { 85 struct device *dev = chan->mbox->dev; 86 struct exynos_mbox *exynos_mbox = dev_get_drvdata(dev); 87 struct exynos_mbox_msg *msg = data; 88 89 if (msg->chan_id >= exynos_mbox->mbox->num_chans) { 90 dev_err(dev, "Invalid channel ID %d\n", msg->chan_id); 91 return -EINVAL; 92 } 93 94 if (msg->chan_type != EXYNOS_MBOX_CHAN_TYPE_DOORBELL) { 95 dev_err(dev, "Unsupported channel type [%d]\n", msg->chan_type); 96 return -EINVAL; 97 } 98 99 /* Ring the doorbell */ 100 writel(BIT(msg->chan_id) << exynos_mbox->data->intgr_shift, 101 exynos_mbox->regs + exynos_mbox->data->intgr); 102 103 return 0; 104 } 105 106 static const struct mbox_chan_ops exynos_mbox_chan_ops = { 107 .send_data = exynos_mbox_send_data, 108 }; 109 110 static struct mbox_chan *exynos_mbox_of_xlate(struct mbox_controller *mbox, 111 const struct of_phandle_args *sp) 112 { 113 int i; 114 115 if (sp->args_count != 0) 116 return ERR_PTR(-EINVAL); 117 118 /* 119 * Return the first available channel. When we don't pass the 120 * channel ID from device tree, each channel populated by the driver is 121 * just a software construct or a virtual channel. We use 'void *data' 122 * in send_data() to pass the channel identifiers. 123 */ 124 for (i = 0; i < mbox->num_chans; i++) 125 if (mbox->chans[i].cl == NULL) 126 return &mbox->chans[i]; 127 return ERR_PTR(-EINVAL); 128 } 129 130 static const struct of_device_id exynos_mbox_match[] = { 131 { 132 .compatible = "google,gs101-mbox", 133 .data = &exynos_gs101_mbox_data 134 }, 135 { 136 .compatible = "samsung,exynos850-mbox", 137 .data = &exynos850_mbox_data 138 }, 139 {}, 140 }; 141 MODULE_DEVICE_TABLE(of, exynos_mbox_match); 142 143 static int exynos_mbox_probe(struct platform_device *pdev) 144 { 145 const struct exynos_mbox_driver_data *data; 146 struct device *dev = &pdev->dev; 147 struct exynos_mbox *exynos_mbox; 148 struct mbox_controller *mbox; 149 struct mbox_chan *chans; 150 struct clk *pclk; 151 152 data = device_get_match_data(&pdev->dev); 153 if (!data) 154 return -ENODEV; 155 156 exynos_mbox = devm_kzalloc(dev, sizeof(*exynos_mbox), GFP_KERNEL); 157 if (!exynos_mbox) 158 return -ENOMEM; 159 160 mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); 161 if (!mbox) 162 return -ENOMEM; 163 164 chans = devm_kcalloc(dev, data->num_chans, sizeof(*chans), GFP_KERNEL); 165 if (!chans) 166 return -ENOMEM; 167 168 exynos_mbox->regs = devm_platform_ioremap_resource(pdev, 0); 169 if (IS_ERR(exynos_mbox->regs)) 170 return PTR_ERR(exynos_mbox->regs); 171 172 pclk = devm_clk_get_enabled(dev, "pclk"); 173 if (IS_ERR(pclk)) 174 return dev_err_probe(dev, PTR_ERR(pclk), 175 "Failed to enable clock.\n"); 176 177 exynos_mbox->data = data; 178 mbox->num_chans = data->num_chans; 179 mbox->chans = chans; 180 mbox->dev = dev; 181 mbox->ops = &exynos_mbox_chan_ops; 182 mbox->of_xlate = exynos_mbox_of_xlate; 183 184 exynos_mbox->mbox = mbox; 185 186 platform_set_drvdata(pdev, exynos_mbox); 187 188 /* Mask out all interrupts. We support just polling channels for now. */ 189 writel(data->intmr_mask, exynos_mbox->regs + data->intmr); 190 191 return devm_mbox_controller_register(dev, mbox); 192 } 193 194 static struct platform_driver exynos_mbox_driver = { 195 .probe = exynos_mbox_probe, 196 .driver = { 197 .name = "exynos-acpm-mbox", 198 .of_match_table = exynos_mbox_match, 199 }, 200 }; 201 module_platform_driver(exynos_mbox_driver); 202 203 MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@linaro.org>"); 204 MODULE_DESCRIPTION("Samsung Exynos mailbox driver"); 205 MODULE_LICENSE("GPL"); 206