0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/acpi.h>
0009 #include <linux/delay.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/io.h>
0012 #include <linux/mailbox_controller.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/spinlock.h>
0017
0018 #define MBOX_CON_NAME "slimpro-mbox"
0019 #define MBOX_REG_SET_OFFSET 0x1000
0020 #define MBOX_CNT 8
0021 #define MBOX_STATUS_AVAIL_MASK BIT(16)
0022 #define MBOX_STATUS_ACK_MASK BIT(0)
0023
0024
0025 #define REG_DB_IN 0x00
0026 #define REG_DB_DIN0 0x04
0027 #define REG_DB_DIN1 0x08
0028 #define REG_DB_OUT 0x10
0029 #define REG_DB_DOUT0 0x14
0030 #define REG_DB_DOUT1 0x18
0031 #define REG_DB_STAT 0x20
0032 #define REG_DB_STATMASK 0x24
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 struct slimpro_mbox_chan {
0044 struct device *dev;
0045 struct mbox_chan *chan;
0046 void __iomem *reg;
0047 int irq;
0048 u32 rx_msg[3];
0049 };
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 struct slimpro_mbox {
0063 struct mbox_controller mb_ctrl;
0064 struct slimpro_mbox_chan mc[MBOX_CNT];
0065 struct mbox_chan chans[MBOX_CNT];
0066 };
0067
0068 static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg)
0069 {
0070 writel(msg[1], mb_chan->reg + REG_DB_DOUT0);
0071 writel(msg[2], mb_chan->reg + REG_DB_DOUT1);
0072 writel(msg[0], mb_chan->reg + REG_DB_OUT);
0073 }
0074
0075 static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan)
0076 {
0077 mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0);
0078 mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1);
0079 mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN);
0080 }
0081
0082 static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan)
0083 {
0084 u32 val = readl(mb_chan->reg + REG_DB_STAT);
0085
0086 if (val & MBOX_STATUS_ACK_MASK) {
0087 writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT);
0088 return 1;
0089 }
0090 return 0;
0091 }
0092
0093 static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan)
0094 {
0095 u32 val = readl(mb_chan->reg + REG_DB_STAT);
0096
0097 if (val & MBOX_STATUS_AVAIL_MASK) {
0098 mb_chan_recv_msg(mb_chan);
0099 writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT);
0100 return 1;
0101 }
0102 return 0;
0103 }
0104
0105 static irqreturn_t slimpro_mbox_irq(int irq, void *id)
0106 {
0107 struct slimpro_mbox_chan *mb_chan = id;
0108
0109 if (mb_chan_status_ack(mb_chan))
0110 mbox_chan_txdone(mb_chan->chan, 0);
0111
0112 if (mb_chan_status_avail(mb_chan))
0113 mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg);
0114
0115 return IRQ_HANDLED;
0116 }
0117
0118 static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg)
0119 {
0120 struct slimpro_mbox_chan *mb_chan = chan->con_priv;
0121
0122 mb_chan_send_msg(mb_chan, msg);
0123 return 0;
0124 }
0125
0126 static int slimpro_mbox_startup(struct mbox_chan *chan)
0127 {
0128 struct slimpro_mbox_chan *mb_chan = chan->con_priv;
0129 int rc;
0130 u32 val;
0131
0132 rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0,
0133 MBOX_CON_NAME, mb_chan);
0134 if (unlikely(rc)) {
0135 dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n",
0136 mb_chan->irq);
0137 return rc;
0138 }
0139
0140
0141 writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK,
0142 mb_chan->reg + REG_DB_STAT);
0143
0144 val = readl(mb_chan->reg + REG_DB_STATMASK);
0145 val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
0146 writel(val, mb_chan->reg + REG_DB_STATMASK);
0147
0148 return 0;
0149 }
0150
0151 static void slimpro_mbox_shutdown(struct mbox_chan *chan)
0152 {
0153 struct slimpro_mbox_chan *mb_chan = chan->con_priv;
0154 u32 val;
0155
0156
0157 val = readl(mb_chan->reg + REG_DB_STATMASK);
0158 val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
0159 writel(val, mb_chan->reg + REG_DB_STATMASK);
0160
0161 devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan);
0162 }
0163
0164 static const struct mbox_chan_ops slimpro_mbox_ops = {
0165 .send_data = slimpro_mbox_send_data,
0166 .startup = slimpro_mbox_startup,
0167 .shutdown = slimpro_mbox_shutdown,
0168 };
0169
0170 static int slimpro_mbox_probe(struct platform_device *pdev)
0171 {
0172 struct slimpro_mbox *ctx;
0173 void __iomem *mb_base;
0174 int rc;
0175 int i;
0176
0177 ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL);
0178 if (!ctx)
0179 return -ENOMEM;
0180
0181 platform_set_drvdata(pdev, ctx);
0182
0183 mb_base = devm_platform_ioremap_resource(pdev, 0);
0184 if (IS_ERR(mb_base))
0185 return PTR_ERR(mb_base);
0186
0187
0188 for (i = 0; i < MBOX_CNT; i++) {
0189 ctx->mc[i].irq = platform_get_irq(pdev, i);
0190 if (ctx->mc[i].irq < 0) {
0191 if (i == 0) {
0192 dev_err(&pdev->dev, "no available IRQ\n");
0193 return -EINVAL;
0194 }
0195 dev_info(&pdev->dev, "no IRQ for channel %d\n", i);
0196 break;
0197 }
0198
0199 ctx->mc[i].dev = &pdev->dev;
0200 ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET;
0201 ctx->mc[i].chan = &ctx->chans[i];
0202 ctx->chans[i].con_priv = &ctx->mc[i];
0203 }
0204
0205
0206 ctx->mb_ctrl.dev = &pdev->dev;
0207 ctx->mb_ctrl.chans = ctx->chans;
0208 ctx->mb_ctrl.txdone_irq = true;
0209 ctx->mb_ctrl.ops = &slimpro_mbox_ops;
0210 ctx->mb_ctrl.num_chans = i;
0211
0212 rc = devm_mbox_controller_register(&pdev->dev, &ctx->mb_ctrl);
0213 if (rc) {
0214 dev_err(&pdev->dev,
0215 "APM X-Gene SLIMpro MailBox register failed:%d\n", rc);
0216 return rc;
0217 }
0218
0219 dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n");
0220 return 0;
0221 }
0222
0223 static const struct of_device_id slimpro_of_match[] = {
0224 {.compatible = "apm,xgene-slimpro-mbox" },
0225 { },
0226 };
0227 MODULE_DEVICE_TABLE(of, slimpro_of_match);
0228
0229 #ifdef CONFIG_ACPI
0230 static const struct acpi_device_id slimpro_acpi_ids[] = {
0231 {"APMC0D01", 0},
0232 {}
0233 };
0234 MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids);
0235 #endif
0236
0237 static struct platform_driver slimpro_mbox_driver = {
0238 .probe = slimpro_mbox_probe,
0239 .driver = {
0240 .name = "xgene-slimpro-mbox",
0241 .of_match_table = of_match_ptr(slimpro_of_match),
0242 .acpi_match_table = ACPI_PTR(slimpro_acpi_ids)
0243 },
0244 };
0245
0246 static int __init slimpro_mbox_init(void)
0247 {
0248 return platform_driver_register(&slimpro_mbox_driver);
0249 }
0250
0251 static void __exit slimpro_mbox_exit(void)
0252 {
0253 platform_driver_unregister(&slimpro_mbox_driver);
0254 }
0255
0256 subsys_initcall(slimpro_mbox_init);
0257 module_exit(slimpro_mbox_exit);
0258
0259 MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver");
0260 MODULE_LICENSE("GPL");