source: rtems-libbsd/rtemsbsd/sys/powerpc/compat.c @ 0f1d2f6

55-freebsd-126-freebsd-12
Last change on this file since 0f1d2f6 was 0f1d2f6, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 10, 2018 at 12:18:05 PM

linux/of_address.h: Add of_translate_address()

Update #3277.

  • Property mode set to 100644
File size: 11.0 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2#include <rtems/bsd/local/opt_dpaa.h>
3
4/*
5 * Copyright (c) 2015, 2018 embedded brains GmbH
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <linux/slab.h>
31
32MALLOC_DEFINE(M_KMALLOC, "kmalloc", "Linux kmalloc compatibility");
33
34#include <bsp/fdt.h>
35
36#include <linux/of.h>
37
38const void *
39of_get_property(const struct device_node *dn, const char *name, int *len)
40{
41        const void *fdt = bsp_fdt_get();
42
43        return (fdt_getprop(fdt, dn->offset, name, len));
44}
45
46int
47of_property_read_u32_array(const struct device_node *dn, const char *name,
48    u32 *vals, size_t n)
49{
50        const u32 *prop_vals;
51        int len;
52
53        prop_vals = of_get_property(dn, name, &len);
54        if (prop_vals == NULL) {
55                return (-EINVAL);
56        }
57
58        if (len != n * sizeof(*vals)) {
59                return (-EOVERFLOW);
60        }
61
62        while (n > 0) {
63                *vals = fdt32_to_cpu(*prop_vals);
64                ++vals;
65                ++prop_vals;
66                --n;
67        }
68
69        return (0);
70}
71
72bool
73of_device_is_available(const struct device_node *dn)
74{
75        const char *status;
76        int len;
77
78        status = of_get_property(dn, "status", &len);
79        return (status == NULL ||
80            (len > 0 && (strcmp(status, "okay") == 0 ||
81            strcmp(status, "ok") == 0)));
82}
83
84int
85of_device_is_compatible(const struct device_node *dn, const char *name)
86{
87        const void *fdt = bsp_fdt_get();
88
89        return (fdt_node_check_compatible(fdt, dn->offset, name) == 0);
90}
91
92struct device_node *
93of_find_node_by_path(struct device_node *dns, const char *path)
94{
95        const void *fdt = bsp_fdt_get();
96        int node;
97
98        memset(dns, 0, sizeof(*dns));
99
100        node = fdt_path_offset(fdt, path);
101        if (node < 0)
102                return (NULL);
103
104        dns->offset = node;
105        return (dns);
106}
107
108struct device_node *
109of_find_compatible_node(struct device_node *dns, const struct device_node *dn,
110    const char *type, const char *compatible)
111{
112        const void *fdt = bsp_fdt_get();
113        int node;
114
115        (void)type;
116
117        if (dn != NULL) {
118                node = dn->offset;
119        } else {
120                node = 0;
121        }
122
123        memset(dns, 0, sizeof(*dns));
124
125        while (1) {
126                int err;
127
128                node = fdt_next_node(fdt, node, NULL);
129                if (node < 0)
130                        return (NULL);
131
132                err = fdt_node_check_compatible(fdt, node, compatible);
133                if (err == 0) {
134                        dns->offset = node;
135                        return (dns);
136                }
137        }
138}
139
140uint64_t
141of_read_number(const uint32_t *cell, int size)
142{
143        uint64_t number;
144
145        number = 0;
146
147        while (size > 0) {
148                number = (number << 32) | fdt32_to_cpu(*cell);
149                ++cell;
150                --size;
151        }
152
153        return (number);
154}
155
156struct device_node *
157of_parse_phandle(struct device_node *dns, struct device_node *dn,
158    const char *phandle_name, int index)
159{
160        const void *fdt = bsp_fdt_get();
161        const fdt32_t *phandle;
162        int node;
163        int len;
164
165        phandle = fdt_getprop(fdt, dn->offset, phandle_name, &len);
166        if (phandle == NULL || (len / (int) sizeof(*phandle)) <= index) {
167                return (NULL);
168        }
169
170        node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(phandle[index]));
171        if (node < 0) {
172                return (NULL);
173        }
174
175        dns->offset = node;
176        dns->full_name = NULL;
177        return (dns);
178}
179
180int
181of_count_phandle_with_args(struct device_node *dn, const char *list_name,
182    const char *cells_name)
183{
184        const void *fdt = bsp_fdt_get();
185        const fdt32_t *phandle;
186        int len;
187
188        BSD_ASSERT(cells_name == NULL);
189
190        phandle = fdt_getprop(fdt, dn->offset, list_name, &len);
191        if (phandle == NULL) {
192                return (-ENOENT);
193        }
194
195        return (len / (int)sizeof(*phandle));
196}
197
198#include <linux/of_address.h>
199#include <linux/of_irq.h>
200
201static int
202get_cells(const void *fdt, int node, const char *name)
203{
204        const fdt32_t *c;
205        int len;
206        int val;
207
208        do {
209                c = fdt_getprop(fdt, node, name, &len);
210                if (c != NULL) {
211                        if (len != sizeof(*c))
212                                return (-EINVAL);
213                        val = fdt32_to_cpu(*c);
214                        if (val <= 0 ||
215                            val > sizeof(resource_size_t) / sizeof(*c))
216                                return (-EINVAL);
217                        return (val);
218                }
219                node = fdt_parent_offset(fdt, node);
220        } while (node >= 0);
221
222        return (-EINVAL);
223}
224
225static int
226get_address_cells(const void *fdt, int node)
227{
228
229        return (get_cells(fdt, node, "#address-cells"));
230}
231
232static int
233get_size_cells(const void *fdt, int node)
234{
235
236        return (get_cells(fdt, node, "#size-cells"));
237}
238
239int
240of_n_addr_cells(struct device_node *dn)
241{
242
243        return (get_address_cells(bsp_fdt_get(), dn->offset));
244}
245
246int
247of_n_size_cells(struct device_node *dn)
248{
249
250        return (get_size_cells(bsp_fdt_get(), dn->offset));
251}
252
253static uint64_t
254translate_address(const char *fdt, int node, int ac, int sc,
255    const uint32_t *addr)
256{
257        int pac;
258        int psc;
259        uint64_t taddr;
260
261        taddr = of_read_number(addr, ac);
262
263        node = fdt_parent_offset(fdt, node);
264        if (node < 0)
265                return (OF_BAD_ADDR);
266
267        for (;;) {
268                int len;
269                int parent;
270                const uint32_t *ranges;
271                uint64_t offset;
272
273                parent = fdt_parent_offset(fdt, node);
274                if (parent < 0)
275                        break;
276
277                pac = get_address_cells(fdt, parent);
278                if (pac < 0)
279                        return (OF_BAD_ADDR);
280
281                psc = get_size_cells(fdt, parent);
282                if (psc < 0)
283                        return (OF_BAD_ADDR);
284
285                ranges = fdt_getprop(fdt, node, "ranges", &len);
286                if (ranges == NULL || len == 0)
287                        break;
288
289                if (len != (ac + pac + sc) * 4)
290                        return (OF_BAD_ADDR);
291
292                if (of_read_number(&ranges[0], ac) != 0)
293                        return (OF_BAD_ADDR);
294
295                offset = of_read_number(&ranges[ac], pac);
296                taddr += offset;
297
298                node = parent;
299                ac = pac;
300                sc = psc;
301        }
302
303        return (taddr);
304}
305
306uint64_t
307of_translate_address(struct device_node *dn, const uint32_t *addr)
308{
309        const void *fdt = bsp_fdt_get();
310        int node;
311        int ac;
312        int sc;
313
314        node = dn->offset;
315
316        ac = get_address_cells(fdt, node);
317        if (ac < 0)
318                return (OF_BAD_ADDR);
319
320        sc = get_size_cells(fdt, node);
321        if (sc < 0)
322                return (OF_BAD_ADDR);
323
324        return (translate_address(fdt, node, ac, sc, addr));
325}
326
327int
328of_address_to_resource(struct device_node *dn, int index,
329    struct resource *res)
330{
331        const void *fdt = bsp_fdt_get();
332        int ac;
333        int sc;
334        int len;
335        const fdt32_t *p;
336        int i;
337
338        memset(res, 0, sizeof(*res));
339
340        ac = get_address_cells(fdt, dn->offset);
341        if (ac < 0)
342                return (-EINVAL);
343
344        sc = get_size_cells(fdt, dn->offset);
345        if (sc < 0)
346                return (-EINVAL);
347
348        p = fdt_getprop(fdt, dn->offset, "reg", &len);
349        if (p == NULL)
350                return (-EINVAL);
351
352        len /= sizeof(*p);
353        i = index * (ac + sc);
354        if (i + ac + sc > len)
355                return (-EINVAL);
356
357        while (ac > 0) {
358                res->start = (res->start << 32) | fdt32_to_cpu(p[i]);
359                ++i;
360                --ac;
361        }
362
363        while (sc > 0) {
364                res->end = (res->end << 32) | fdt32_to_cpu(p[i]);
365                ++i;
366                --sc;
367        }
368        res->end += res->start;
369
370        return (0);
371}
372
373int
374of_irq_to_resource(struct device_node *dn, int index,
375    struct resource *res)
376{
377        const void *fdt = bsp_fdt_get();
378        int len;
379        const fdt32_t *p;
380        int i;
381        int irq;
382
383        if (res != NULL)
384                memset(res, 0, sizeof(*res));
385
386        p = fdt_getprop(fdt, dn->offset, "interrupts", &len);
387        if (p == NULL)
388                return (-EINVAL);
389
390        i = index * 16;
391        if (i + 16 > len)
392                return (-EINVAL);
393
394        irq = (int)fdt32_to_cpu(p[i / sizeof(*p)]);
395#ifdef __PPC__
396        /* FIXME */
397        irq -= 16;
398#endif
399
400        if (res != NULL) {
401                res->start = irq;
402                res->end = irq;
403        }
404
405        return (irq);
406}
407
408#include <linux/of_net.h>
409#include <linux/if_ether.h>
410#include <linux/phy.h>
411
412static const char * const phy_modes[] = {
413        [PHY_INTERFACE_MODE_MII]        = "mii",
414        [PHY_INTERFACE_MODE_GMII]       = "gmii",
415        [PHY_INTERFACE_MODE_SGMII]      = "sgmii",
416        [PHY_INTERFACE_MODE_TBI]        = "tbi",
417        [PHY_INTERFACE_MODE_REVMII]     = "rev-mii",
418        [PHY_INTERFACE_MODE_RMII]       = "rmii",
419        [PHY_INTERFACE_MODE_RGMII]      = "rgmii",
420        [PHY_INTERFACE_MODE_RGMII_ID]   = "rgmii-id",
421        [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
422        [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
423        [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
424        [PHY_INTERFACE_MODE_SMII]       = "smii",
425        [PHY_INTERFACE_MODE_XGMII]      = "xgmii",
426        [PHY_INTERFACE_MODE_MOCA]       = "moca",
427        [PHY_INTERFACE_MODE_QSGMII]     = "qsgmii"
428};
429
430int
431of_get_phy_mode(struct device_node *dn)
432{
433        const void *fdt = bsp_fdt_get();
434        int len;
435        const char *p;
436        int i;
437
438        p = fdt_getprop(fdt, dn->offset, "phy-mode", &len);
439
440        if (p == NULL) {
441                p = fdt_getprop(fdt, dn->offset, "phy-connection-type", &len);
442        }
443
444        if (p == NULL) {
445                return (-ENODEV);
446        }
447
448        for (i = 0; i < ARRAY_SIZE(phy_modes); i++) {
449                if (phy_modes[i] != NULL && strcmp(p, phy_modes[i]) == 0) {
450                        return (i);
451                }
452        }
453
454        return (-ENODEV);
455}
456
457static const void *
458get_mac_address(struct device_node *dn, const char *name)
459{
460        const void *fdt = bsp_fdt_get();
461        int len;
462        const fdt32_t *p;
463
464        p = fdt_getprop(fdt, dn->offset, name, &len);
465        if (p == NULL || len != ETH_ALEN) {
466                return (NULL);
467        }
468
469        return (p);
470}
471
472const void *
473of_get_mac_address(struct device_node *dn)
474{
475        const void *addr;
476
477        addr = get_mac_address(dn, "mac-address");
478        if (addr != NULL) {
479                return addr;
480        }
481
482        return get_mac_address(dn, "local-mac-address");
483}
484
485#include <linux/interrupt.h>
486
487struct arg_wrapper {
488        irq_handler_t handler;
489        unsigned int irq;
490        void *arg;
491};
492
493static void
494handler_wrapper(void *arg)
495{
496        struct arg_wrapper *aw = arg;
497
498        (*aw->handler)(aw->irq, aw->arg);
499}
500
501int __must_check
502request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
503    const char *name, void *arg)
504{
505        struct arg_wrapper *aw;
506        rtems_status_code sc;
507
508        aw = kmalloc(sizeof(*aw), GFP_KERNEL);
509        if (aw == NULL)
510                return (-ENOMEM);
511
512        aw->handler = handler;
513        aw->irq = irq;
514        aw->arg = arg;
515        sc = rtems_interrupt_server_handler_install(RTEMS_ID_NONE, irq, name,
516            RTEMS_INTERRUPT_SHARED, handler_wrapper, aw);
517        if (sc != RTEMS_SUCCESSFUL)
518                return (-EINVAL);
519
520        return (0);
521}
522
523#include <linux/bitrev.h>
524
525const uint8_t bitrev_nibbles[16] = {
526        0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
527};
528
529#include <linux/platform_device.h>
530
531struct resource *
532platform_get_resource(struct resource *res, struct platform_device *pdev,
533    unsigned int type, unsigned int num)
534{
535        struct device_node *dn;
536        int ret;
537
538        dn = pdev->dev.of_node;
539
540        switch (type) {
541        case IORESOURCE_MEM:
542                ret = of_address_to_resource(dn, num, res);
543                if (ret == 0)
544                        return res;
545        case IORESOURCE_IRQ:
546                ret = of_irq_to_resource(dn, num, res);
547                if (ret >= 0)
548                        return res;
549        default:
550                break;
551        }
552
553        return (NULL);
554}
555
556int platform_get_irq(struct platform_device *pdev, unsigned int num)
557{
558        struct resource res_storage;
559        struct resource *res;
560
561        res = platform_get_resource(&res_storage, pdev, IORESOURCE_IRQ, num);
562        return (res != NULL ? res->start : -ENXIO);
563}
Note: See TracBrowser for help on using the repository browser.