OpenCores
URL https://opencores.org/ocsvn/funbase_ip_library/funbase_ip_library/trunk

Subversion Repositories funbase_ip_library

[/] [funbase_ip_library/] [trunk/] [TUT/] [ip.swp.api/] [openmcapi/] [1.0/] [libmcapi/] [shm/] [linux/] [kmod/] [mpc85xx.c] - Blame information for rev 145

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 145 lanttu
/*
2
 * Copyright (c) 2010, Mentor Graphics Corporation
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of the <ORGANIZATION> nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * Alternatively, this software may be distributed under the terms of the
18
 * GNU General Public License ("GPL") version 2 as published by the Free
19
 * Software Foundation.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
 * POSSIBILITY OF SUCH DAMAGE.
32
 */
33
 
34
#include <linux/kernel.h>
35
#include <linux/mm.h>
36
#include <linux/io.h>
37
#include <linux/module.h>
38
#include <linux/mod_devicetable.h>
39
#include <linux/of_platform.h>
40
 
41
#include <asm/io.h>
42
#include <asm/pgtable.h>
43
#include <asm/prom.h>
44
#include <asm/of_device.h>
45
#include <asm/fsl_msg.h>
46
 
47
#include "mcomm.h"
48
 
49
#define MESSAGE_VAL 1
50
 
51
struct notification {
52
        u32 core_id;
53
        u32 msg_num;
54
};
55
 
56
static struct mcomm_mpc85xx_data {
57
        struct fsl_msg_unit **notifications; /* Assumes contiguous PIRs. */
58
        int nr_notifications;
59
} mcomm_mpc85xx_data;
60
 
61
 
62
 
63
static pgprot_t mcomm_mpc85xx_mmap_pgprot(struct vm_area_struct *vma)
64
{
65
        return pgprot_cached(vma->vm_page_prot);
66
}
67
 
68
static void __iomem *mcomm_mpc85xx_ioremap(unsigned long phys_addr, size_t size)
69
{
70
        return ioremap_prot(phys_addr, size, _PAGE_COHERENT);
71
}
72
 
73
static void mcomm_mpc85xx_notify(u32 core_id)
74
{
75
        fsl_send_msg(mcomm_mpc85xx_data.notifications[core_id], MESSAGE_VAL);
76
}
77
 
78
static unsigned long mcomm_mpc85xx_cpuid(void)
79
{
80
        return mfspr(SPRN_PIR);
81
}
82
 
83
static void mcomm_mpc85xx_ack(void)
84
{
85
        fsl_clear_msg(mcomm_mpc85xx_data.notifications[mcomm_mpc85xx_cpuid()]);
86
}
87
 
88
static struct mcomm_platform_ops mcomm_mpc85xx_ops = {
89
        .mmap_pgprot = mcomm_mpc85xx_mmap_pgprot,
90
        .map = mcomm_mpc85xx_ioremap,
91
        .notify = mcomm_mpc85xx_notify,
92
        .ack = mcomm_mpc85xx_ack,
93
        .cpuid = mcomm_mpc85xx_cpuid,
94
};
95
 
96
static void mcomm_mpc85xx_hwuninit(void)
97
{
98
        int i;
99
 
100
        for (i = 0; i < mcomm_mpc85xx_data.nr_notifications; i++) {
101
                /* XXX leaves MER enabled? */
102
                fsl_release_msg_unit(mcomm_mpc85xx_data.notifications[i]);
103
        }
104
}
105
 
106
static int mcomm_mpc85xx_hwinit(const struct notification notifications[],
107
                                 int nr_notifications)
108
{
109
        struct mcomm_mpc85xx_data *data = &mcomm_mpc85xx_data;
110
        unsigned int cur_cpu = mcomm_mpc85xx_cpuid();
111
        struct fsl_msg_unit *self;
112
        int i;
113
 
114
        for (i = 0; i < nr_notifications; i++) {
115
                u32 core_id = notifications[i].core_id;
116
                u32 msg_num = notifications[i].msg_num;
117
                struct fsl_msg_unit *msgunit;
118
 
119
                msgunit = fsl_request_msg(msg_num);
120
                BUG_ON(IS_ERR(msgunit));
121
                data->notifications[core_id] = msgunit;
122
        }
123
 
124
        self = data->notifications[cur_cpu];
125
 
126
        /* Set our MIDR and enable ourselves in in MER. */
127
        fsl_set_msg_dest(self, cur_cpu);
128
        fsl_enable_msg(self);
129
 
130
        return self->irq;
131
}
132
 
133
static int mcomm_mpc85xx_remove(struct of_device *odev)
134
{
135
        struct mcomm_mpc85xx_data *data = &mcomm_mpc85xx_data;
136
 
137
        mcomm_remove_region(&odev->dev);
138
 
139
        mcomm_mpc85xx_hwuninit();
140
 
141
        kfree(data->notifications);
142
 
143
        return 0;
144
}
145
 
146
static int mcomm_mpc85xx_probe(struct of_device *odev,
147
                               const struct of_device_id *match)
148
{
149
        struct resource mem;
150
        struct resource irq;
151
        struct mcomm_mpc85xx_data *data = &mcomm_mpc85xx_data;
152
        const u32 *prop;
153
        int len;
154
        int rc;
155
        static int initialized;
156
 
157
        if (initialized++)
158
                return -EEXIST;
159
 
160
        rc = of_address_to_resource(odev->node, 0, &mem);
161
        if (rc < 0) {
162
                dev_err(&odev->dev, "invalid address\n");
163
                rc = -EINVAL;
164
                goto out1;
165
        }
166
 
167
        prop = of_get_property(odev->node, "notifications", &len);
168
        if (!prop) {
169
                dev_err(&odev->dev, "no message index\n");
170
                rc = -EINVAL;
171
                goto out1;
172
        }
173
        data->nr_notifications = len / sizeof(u32) / 2;
174
        data->notifications =
175
                    kmalloc(sizeof(data->notifications[0]) * data->nr_notifications,
176
                    GFP_KERNEL);
177
        if (!data->notifications) {
178
                rc = -ENOMEM;
179
                goto out1;
180
        }
181
 
182
        irq.start = mcomm_mpc85xx_hwinit((struct notification *)prop,
183
                                          data->nr_notifications);
184
 
185
        rc = mcomm_new_region(&odev->dev, &mem, &irq);
186
        /* XXX check error path */
187
        if (rc)
188
                goto out2;
189
 
190
        return 0;
191
 
192
out2:
193
        mcomm_mpc85xx_remove(odev);
194
out1:
195
        return rc;
196
}
197
 
198
 
199
static const struct of_device_id mcomm_match_table[] = {
200
        { .compatible   = "ment,mcomm", },
201
        {}
202
};
203
 
204
static struct of_platform_driver mcomm_of_driver = {
205
        .name = "mcomm",
206
        .match_table = mcomm_match_table,
207
 
208
        .probe = mcomm_mpc85xx_probe,
209
        .remove = mcomm_mpc85xx_remove,
210
};
211
 
212
/* Because our node isn't under the localbus or soc nodes, platform code won't
213
 * automatically create an of_device for it, so we have to do it ourselves. */
214
static void mcomm_mpc85xx_devices_find(void)
215
{
216
        struct device_node *node = NULL;
217
        int i = 0;
218
 
219
        for (node = NULL;
220
                 (node = of_find_compatible_node(node, NULL, "ment,mcomm")) != NULL;) {
221
                char bus_id[32];
222
                sprintf(bus_id, "%s.%d", node->name, i++);
223
                of_platform_device_create(node, bus_id, NULL);
224
        }
225
}
226
 
227
static void mcomm_mpc85xx_devices_remove(void)
228
{
229
        struct device_node *node = NULL;
230
 
231
        for (node = NULL;
232
                 (node = of_find_compatible_node(node, NULL, "ment,mcomm")) != NULL;) {
233
                struct of_device *odev = of_find_device_by_node(node);
234
 
235
                if (odev)
236
                        of_device_unregister(odev);
237
        }
238
}
239
 
240
static int __init mcomm_mpc85xx_modinit(void)
241
{
242
        int rc;
243
 
244
        rc = mcomm_init(&mcomm_mpc85xx_ops, THIS_MODULE);
245
        if (rc) {
246
                printk(KERN_ERR "%s: mcomm_init failed\n", __func__);
247
                goto out1;
248
        }
249
 
250
        rc = of_register_platform_driver(&mcomm_of_driver);
251
        if (rc) {
252
                printk(KERN_ERR "%s: failed to register platform driver\n", __func__);
253
                goto out2;
254
        }
255
 
256
        mcomm_mpc85xx_devices_find();
257
 
258
        return 0;
259
 
260
out2:
261
        mcomm_exit();
262
out1:
263
        return rc;
264
}
265
module_init(mcomm_mpc85xx_modinit);
266
 
267
static void mcomm_mpc85xx_modexit(void)
268
{
269
        mcomm_mpc85xx_devices_remove();
270
        mcomm_exit();
271
        return of_unregister_platform_driver(&mcomm_of_driver);
272
}
273
module_exit(mcomm_mpc85xx_modexit);
274
 
275
MODULE_LICENSE("GPL v2");
276
MODULE_AUTHOR("Hollis Blanchard <hollis_blanchard@mentor.com>");
277
MODULE_DESCRIPTION("Shared memory platform support for multi-core e500 processors using MPIC");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.