Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
0004  *                    <benh@kernel.crashing.org>
0005  */
0006 
0007 #undef DEBUG
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/export.h>
0011 #include <linux/of_address.h>
0012 #include <asm/dcr.h>
0013 
0014 #ifdef CONFIG_PPC_DCR_MMIO
0015 static struct device_node *find_dcr_parent(struct device_node *node)
0016 {
0017     struct device_node *par, *tmp;
0018     const u32 *p;
0019 
0020     for (par = of_node_get(node); par;) {
0021         if (of_get_property(par, "dcr-controller", NULL))
0022             break;
0023         p = of_get_property(par, "dcr-parent", NULL);
0024         tmp = par;
0025         if (p == NULL)
0026             par = of_get_parent(par);
0027         else
0028             par = of_find_node_by_phandle(*p);
0029         of_node_put(tmp);
0030     }
0031     return par;
0032 }
0033 #endif
0034 
0035 #if defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO)
0036 
0037 bool dcr_map_ok_generic(dcr_host_t host)
0038 {
0039     if (host.type == DCR_HOST_NATIVE)
0040         return dcr_map_ok_native(host.host.native);
0041     else if (host.type == DCR_HOST_MMIO)
0042         return dcr_map_ok_mmio(host.host.mmio);
0043     else
0044         return false;
0045 }
0046 EXPORT_SYMBOL_GPL(dcr_map_ok_generic);
0047 
0048 dcr_host_t dcr_map_generic(struct device_node *dev,
0049                unsigned int dcr_n,
0050                unsigned int dcr_c)
0051 {
0052     dcr_host_t host;
0053     struct device_node *dp;
0054     const char *prop;
0055 
0056     host.type = DCR_HOST_INVALID;
0057 
0058     dp = find_dcr_parent(dev);
0059     if (dp == NULL)
0060         return host;
0061 
0062     prop = of_get_property(dp, "dcr-access-method", NULL);
0063 
0064     pr_debug("dcr_map_generic(dcr-access-method = %s)\n", prop);
0065 
0066     if (!strcmp(prop, "native")) {
0067         host.type = DCR_HOST_NATIVE;
0068         host.host.native = dcr_map_native(dev, dcr_n, dcr_c);
0069     } else if (!strcmp(prop, "mmio")) {
0070         host.type = DCR_HOST_MMIO;
0071         host.host.mmio = dcr_map_mmio(dev, dcr_n, dcr_c);
0072     }
0073 
0074     of_node_put(dp);
0075     return host;
0076 }
0077 EXPORT_SYMBOL_GPL(dcr_map_generic);
0078 
0079 void dcr_unmap_generic(dcr_host_t host, unsigned int dcr_c)
0080 {
0081     if (host.type == DCR_HOST_NATIVE)
0082         dcr_unmap_native(host.host.native, dcr_c);
0083     else if (host.type == DCR_HOST_MMIO)
0084         dcr_unmap_mmio(host.host.mmio, dcr_c);
0085     else /* host.type == DCR_HOST_INVALID */
0086         WARN_ON(true);
0087 }
0088 EXPORT_SYMBOL_GPL(dcr_unmap_generic);
0089 
0090 u32 dcr_read_generic(dcr_host_t host, unsigned int dcr_n)
0091 {
0092     if (host.type == DCR_HOST_NATIVE)
0093         return dcr_read_native(host.host.native, dcr_n);
0094     else if (host.type == DCR_HOST_MMIO)
0095         return dcr_read_mmio(host.host.mmio, dcr_n);
0096     else /* host.type == DCR_HOST_INVALID */
0097         WARN_ON(true);
0098     return 0;
0099 }
0100 EXPORT_SYMBOL_GPL(dcr_read_generic);
0101 
0102 void dcr_write_generic(dcr_host_t host, unsigned int dcr_n, u32 value)
0103 {
0104     if (host.type == DCR_HOST_NATIVE)
0105         dcr_write_native(host.host.native, dcr_n, value);
0106     else if (host.type == DCR_HOST_MMIO)
0107         dcr_write_mmio(host.host.mmio, dcr_n, value);
0108     else /* host.type == DCR_HOST_INVALID */
0109         WARN_ON(true);
0110 }
0111 EXPORT_SYMBOL_GPL(dcr_write_generic);
0112 
0113 #endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
0114 
0115 unsigned int dcr_resource_start(const struct device_node *np,
0116                 unsigned int index)
0117 {
0118     unsigned int ds;
0119     const u32 *dr = of_get_property(np, "dcr-reg", &ds);
0120 
0121     if (dr == NULL || ds & 1 || index >= (ds / 8))
0122         return 0;
0123 
0124     return dr[index * 2];
0125 }
0126 EXPORT_SYMBOL_GPL(dcr_resource_start);
0127 
0128 unsigned int dcr_resource_len(const struct device_node *np, unsigned int index)
0129 {
0130     unsigned int ds;
0131     const u32 *dr = of_get_property(np, "dcr-reg", &ds);
0132 
0133     if (dr == NULL || ds & 1 || index >= (ds / 8))
0134         return 0;
0135 
0136     return dr[index * 2 + 1];
0137 }
0138 EXPORT_SYMBOL_GPL(dcr_resource_len);
0139 
0140 #ifdef CONFIG_PPC_DCR_MMIO
0141 
0142 static u64 of_translate_dcr_address(struct device_node *dev,
0143                     unsigned int dcr_n,
0144                     unsigned int *out_stride)
0145 {
0146     struct device_node *dp;
0147     const u32 *p;
0148     unsigned int stride;
0149     u64 ret = OF_BAD_ADDR;
0150 
0151     dp = find_dcr_parent(dev);
0152     if (dp == NULL)
0153         return OF_BAD_ADDR;
0154 
0155     /* Stride is not properly defined yet, default to 0x10 for Axon */
0156     p = of_get_property(dp, "dcr-mmio-stride", NULL);
0157     stride = (p == NULL) ? 0x10 : *p;
0158 
0159     /* XXX FIXME: Which property name is to use of the 2 following ? */
0160     p = of_get_property(dp, "dcr-mmio-range", NULL);
0161     if (p == NULL)
0162         p = of_get_property(dp, "dcr-mmio-space", NULL);
0163     if (p == NULL)
0164         goto done;
0165 
0166     /* Maybe could do some better range checking here */
0167     ret = of_translate_address(dp, p);
0168     if (ret != OF_BAD_ADDR)
0169         ret += (u64)(stride) * (u64)dcr_n;
0170     if (out_stride)
0171         *out_stride = stride;
0172 
0173  done:
0174     of_node_put(dp);
0175     return ret;
0176 }
0177 
0178 dcr_host_mmio_t dcr_map_mmio(struct device_node *dev,
0179                  unsigned int dcr_n,
0180                  unsigned int dcr_c)
0181 {
0182     dcr_host_mmio_t ret = { .token = NULL, .stride = 0, .base = dcr_n };
0183     u64 addr;
0184 
0185     pr_debug("dcr_map(%pOF, 0x%x, 0x%x)\n",
0186          dev, dcr_n, dcr_c);
0187 
0188     addr = of_translate_dcr_address(dev, dcr_n, &ret.stride);
0189     pr_debug("translates to addr: 0x%llx, stride: 0x%x\n",
0190          (unsigned long long) addr, ret.stride);
0191     if (addr == OF_BAD_ADDR)
0192         return ret;
0193     pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride);
0194     ret.token = ioremap(addr, dcr_c * ret.stride);
0195     if (ret.token == NULL)
0196         return ret;
0197     pr_debug("mapped at 0x%p -> base is 0x%p\n",
0198          ret.token, ret.token - dcr_n * ret.stride);
0199     ret.token -= dcr_n * ret.stride;
0200     return ret;
0201 }
0202 EXPORT_SYMBOL_GPL(dcr_map_mmio);
0203 
0204 void dcr_unmap_mmio(dcr_host_mmio_t host, unsigned int dcr_c)
0205 {
0206     dcr_host_mmio_t h = host;
0207 
0208     if (h.token == NULL)
0209         return;
0210     h.token += host.base * h.stride;
0211     iounmap(h.token);
0212     h.token = NULL;
0213 }
0214 EXPORT_SYMBOL_GPL(dcr_unmap_mmio);
0215 
0216 #endif /* defined(CONFIG_PPC_DCR_MMIO) */
0217 
0218 #ifdef CONFIG_PPC_DCR_NATIVE
0219 DEFINE_SPINLOCK(dcr_ind_lock);
0220 EXPORT_SYMBOL_GPL(dcr_ind_lock);
0221 #endif  /* defined(CONFIG_PPC_DCR_NATIVE) */
0222