linux/arch/powerpc/sysdev/dcr.c
<<
>>
Prefs
   1/*
   2 * (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
   3 *                    <benh@kernel.crashing.org>
   4 *
   5 *   This program is free software;  you can redistribute it and/or modify
   6 *   it under the terms of the GNU General Public License as published by
   7 *   the Free Software Foundation; either version 2 of the License, or
   8 *   (at your option) any later version.
   9 *
  10 *   This program is distributed in the hope that it will be useful,
  11 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
  12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  13 *   the GNU General Public License for more details.
  14 *
  15 *   You should have received a copy of the GNU General Public License
  16 *   along with this program;  if not, write to the Free Software
  17 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18 */
  19
  20#undef DEBUG
  21
  22#include <linux/kernel.h>
  23#include <linux/export.h>
  24#include <asm/prom.h>
  25#include <asm/dcr.h>
  26
  27#ifdef CONFIG_PPC_DCR_MMIO
  28static struct device_node *find_dcr_parent(struct device_node *node)
  29{
  30        struct device_node *par, *tmp;
  31        const u32 *p;
  32
  33        for (par = of_node_get(node); par;) {
  34                if (of_get_property(par, "dcr-controller", NULL))
  35                        break;
  36                p = of_get_property(par, "dcr-parent", NULL);
  37                tmp = par;
  38                if (p == NULL)
  39                        par = of_get_parent(par);
  40                else
  41                        par = of_find_node_by_phandle(*p);
  42                of_node_put(tmp);
  43        }
  44        return par;
  45}
  46#endif
  47
  48#if defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO)
  49
  50bool dcr_map_ok_generic(dcr_host_t host)
  51{
  52        if (host.type == DCR_HOST_NATIVE)
  53                return dcr_map_ok_native(host.host.native);
  54        else if (host.type == DCR_HOST_MMIO)
  55                return dcr_map_ok_mmio(host.host.mmio);
  56        else
  57                return 0;
  58}
  59EXPORT_SYMBOL_GPL(dcr_map_ok_generic);
  60
  61dcr_host_t dcr_map_generic(struct device_node *dev,
  62                           unsigned int dcr_n,
  63                           unsigned int dcr_c)
  64{
  65        dcr_host_t host;
  66        struct device_node *dp;
  67        const char *prop;
  68
  69        host.type = DCR_HOST_INVALID;
  70
  71        dp = find_dcr_parent(dev);
  72        if (dp == NULL)
  73                return host;
  74
  75        prop = of_get_property(dp, "dcr-access-method", NULL);
  76
  77        pr_debug("dcr_map_generic(dcr-access-method = %s)\n", prop);
  78
  79        if (!strcmp(prop, "native")) {
  80                host.type = DCR_HOST_NATIVE;
  81                host.host.native = dcr_map_native(dev, dcr_n, dcr_c);
  82        } else if (!strcmp(prop, "mmio")) {
  83                host.type = DCR_HOST_MMIO;
  84                host.host.mmio = dcr_map_mmio(dev, dcr_n, dcr_c);
  85        }
  86
  87        of_node_put(dp);
  88        return host;
  89}
  90EXPORT_SYMBOL_GPL(dcr_map_generic);
  91
  92void dcr_unmap_generic(dcr_host_t host, unsigned int dcr_c)
  93{
  94        if (host.type == DCR_HOST_NATIVE)
  95                dcr_unmap_native(host.host.native, dcr_c);
  96        else if (host.type == DCR_HOST_MMIO)
  97                dcr_unmap_mmio(host.host.mmio, dcr_c);
  98        else /* host.type == DCR_HOST_INVALID */
  99                WARN_ON(true);
 100}
 101EXPORT_SYMBOL_GPL(dcr_unmap_generic);
 102
 103u32 dcr_read_generic(dcr_host_t host, unsigned int dcr_n)
 104{
 105        if (host.type == DCR_HOST_NATIVE)
 106                return dcr_read_native(host.host.native, dcr_n);
 107        else if (host.type == DCR_HOST_MMIO)
 108                return dcr_read_mmio(host.host.mmio, dcr_n);
 109        else /* host.type == DCR_HOST_INVALID */
 110                WARN_ON(true);
 111        return 0;
 112}
 113EXPORT_SYMBOL_GPL(dcr_read_generic);
 114
 115void dcr_write_generic(dcr_host_t host, unsigned int dcr_n, u32 value)
 116{
 117        if (host.type == DCR_HOST_NATIVE)
 118                dcr_write_native(host.host.native, dcr_n, value);
 119        else if (host.type == DCR_HOST_MMIO)
 120                dcr_write_mmio(host.host.mmio, dcr_n, value);
 121        else /* host.type == DCR_HOST_INVALID */
 122                WARN_ON(true);
 123}
 124EXPORT_SYMBOL_GPL(dcr_write_generic);
 125
 126#endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
 127
 128unsigned int dcr_resource_start(const struct device_node *np,
 129                                unsigned int index)
 130{
 131        unsigned int ds;
 132        const u32 *dr = of_get_property(np, "dcr-reg", &ds);
 133
 134        if (dr == NULL || ds & 1 || index >= (ds / 8))
 135                return 0;
 136
 137        return dr[index * 2];
 138}
 139EXPORT_SYMBOL_GPL(dcr_resource_start);
 140
 141unsigned int dcr_resource_len(const struct device_node *np, unsigned int index)
 142{
 143        unsigned int ds;
 144        const u32 *dr = of_get_property(np, "dcr-reg", &ds);
 145
 146        if (dr == NULL || ds & 1 || index >= (ds / 8))
 147                return 0;
 148
 149        return dr[index * 2 + 1];
 150}
 151EXPORT_SYMBOL_GPL(dcr_resource_len);
 152
 153#ifdef CONFIG_PPC_DCR_MMIO
 154
 155u64 of_translate_dcr_address(struct device_node *dev,
 156                             unsigned int dcr_n,
 157                             unsigned int *out_stride)
 158{
 159        struct device_node *dp;
 160        const u32 *p;
 161        unsigned int stride;
 162        u64 ret = OF_BAD_ADDR;
 163
 164        dp = find_dcr_parent(dev);
 165        if (dp == NULL)
 166                return OF_BAD_ADDR;
 167
 168        /* Stride is not properly defined yet, default to 0x10 for Axon */
 169        p = of_get_property(dp, "dcr-mmio-stride", NULL);
 170        stride = (p == NULL) ? 0x10 : *p;
 171
 172        /* XXX FIXME: Which property name is to use of the 2 following ? */
 173        p = of_get_property(dp, "dcr-mmio-range", NULL);
 174        if (p == NULL)
 175                p = of_get_property(dp, "dcr-mmio-space", NULL);
 176        if (p == NULL)
 177                goto done;
 178
 179        /* Maybe could do some better range checking here */
 180        ret = of_translate_address(dp, p);
 181        if (ret != OF_BAD_ADDR)
 182                ret += (u64)(stride) * (u64)dcr_n;
 183        if (out_stride)
 184                *out_stride = stride;
 185
 186 done:
 187        of_node_put(dp);
 188        return ret;
 189}
 190
 191dcr_host_mmio_t dcr_map_mmio(struct device_node *dev,
 192                             unsigned int dcr_n,
 193                             unsigned int dcr_c)
 194{
 195        dcr_host_mmio_t ret = { .token = NULL, .stride = 0, .base = dcr_n };
 196        u64 addr;
 197
 198        pr_debug("dcr_map(%s, 0x%x, 0x%x)\n",
 199                 dev->full_name, dcr_n, dcr_c);
 200
 201        addr = of_translate_dcr_address(dev, dcr_n, &ret.stride);
 202        pr_debug("translates to addr: 0x%llx, stride: 0x%x\n",
 203                 (unsigned long long) addr, ret.stride);
 204        if (addr == OF_BAD_ADDR)
 205                return ret;
 206        pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride);
 207        ret.token = ioremap(addr, dcr_c * ret.stride);
 208        if (ret.token == NULL)
 209                return ret;
 210        pr_debug("mapped at 0x%p -> base is 0x%p\n",
 211                 ret.token, ret.token - dcr_n * ret.stride);
 212        ret.token -= dcr_n * ret.stride;
 213        return ret;
 214}
 215EXPORT_SYMBOL_GPL(dcr_map_mmio);
 216
 217void dcr_unmap_mmio(dcr_host_mmio_t host, unsigned int dcr_c)
 218{
 219        dcr_host_mmio_t h = host;
 220
 221        if (h.token == NULL)
 222                return;
 223        h.token += host.base * h.stride;
 224        iounmap(h.token);
 225        h.token = NULL;
 226}
 227EXPORT_SYMBOL_GPL(dcr_unmap_mmio);
 228
 229#endif /* defined(CONFIG_PPC_DCR_MMIO) */
 230
 231#ifdef CONFIG_PPC_DCR_NATIVE
 232DEFINE_SPINLOCK(dcr_ind_lock);
 233#endif  /* defined(CONFIG_PPC_DCR_NATIVE) */
 234
 235