Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
0004  *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
0005  */
0006 #include <linux/slab.h>
0007 #include <linux/err.h>
0008 #include <linux/init.h>
0009 #include <linux/list.h>
0010 #include <linux/io.h>
0011 #include <linux/of_address.h>
0012 #include <linux/of_device.h>
0013 #include <linux/of_dma.h>
0014 
0015 #define TI_XBAR_DRA7        0
0016 #define TI_XBAR_AM335X      1
0017 static const u32 ti_xbar_type[] = {
0018     [TI_XBAR_DRA7] = TI_XBAR_DRA7,
0019     [TI_XBAR_AM335X] = TI_XBAR_AM335X,
0020 };
0021 
0022 static const struct of_device_id ti_dma_xbar_match[] = {
0023     {
0024         .compatible = "ti,dra7-dma-crossbar",
0025         .data = &ti_xbar_type[TI_XBAR_DRA7],
0026     },
0027     {
0028         .compatible = "ti,am335x-edma-crossbar",
0029         .data = &ti_xbar_type[TI_XBAR_AM335X],
0030     },
0031     {},
0032 };
0033 
0034 /* Crossbar on AM335x/AM437x family */
0035 #define TI_AM335X_XBAR_LINES    64
0036 
0037 struct ti_am335x_xbar_data {
0038     void __iomem *iomem;
0039 
0040     struct dma_router dmarouter;
0041 
0042     u32 xbar_events; /* maximum number of events to select in xbar */
0043     u32 dma_requests; /* number of DMA requests on eDMA */
0044 };
0045 
0046 struct ti_am335x_xbar_map {
0047     u16 dma_line;
0048     u8 mux_val;
0049 };
0050 
0051 static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val)
0052 {
0053     /*
0054      * TPCC_EVT_MUX_60_63 register layout is different than the
0055      * rest, in the sense, that event 63 is mapped to lowest byte
0056      * and event 60 is mapped to highest, handle it separately.
0057      */
0058     if (event >= 60 && event <= 63)
0059         writeb_relaxed(val, iomem + (63 - event % 4));
0060     else
0061         writeb_relaxed(val, iomem + event);
0062 }
0063 
0064 static void ti_am335x_xbar_free(struct device *dev, void *route_data)
0065 {
0066     struct ti_am335x_xbar_data *xbar = dev_get_drvdata(dev);
0067     struct ti_am335x_xbar_map *map = route_data;
0068 
0069     dev_dbg(dev, "Unmapping XBAR event %u on channel %u\n",
0070         map->mux_val, map->dma_line);
0071 
0072     ti_am335x_xbar_write(xbar->iomem, map->dma_line, 0);
0073     kfree(map);
0074 }
0075 
0076 static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec,
0077                        struct of_dma *ofdma)
0078 {
0079     struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
0080     struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev);
0081     struct ti_am335x_xbar_map *map;
0082 
0083     if (dma_spec->args_count != 3)
0084         return ERR_PTR(-EINVAL);
0085 
0086     if (dma_spec->args[2] >= xbar->xbar_events) {
0087         dev_err(&pdev->dev, "Invalid XBAR event number: %d\n",
0088             dma_spec->args[2]);
0089         return ERR_PTR(-EINVAL);
0090     }
0091 
0092     if (dma_spec->args[0] >= xbar->dma_requests) {
0093         dev_err(&pdev->dev, "Invalid DMA request line number: %d\n",
0094             dma_spec->args[0]);
0095         return ERR_PTR(-EINVAL);
0096     }
0097 
0098     /* The of_node_put() will be done in the core for the node */
0099     dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
0100     if (!dma_spec->np) {
0101         dev_err(&pdev->dev, "Can't get DMA master\n");
0102         return ERR_PTR(-EINVAL);
0103     }
0104 
0105     map = kzalloc(sizeof(*map), GFP_KERNEL);
0106     if (!map) {
0107         of_node_put(dma_spec->np);
0108         return ERR_PTR(-ENOMEM);
0109     }
0110 
0111     map->dma_line = (u16)dma_spec->args[0];
0112     map->mux_val = (u8)dma_spec->args[2];
0113 
0114     dma_spec->args[2] = 0;
0115     dma_spec->args_count = 2;
0116 
0117     dev_dbg(&pdev->dev, "Mapping XBAR event%u to DMA%u\n",
0118         map->mux_val, map->dma_line);
0119 
0120     ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val);
0121 
0122     return map;
0123 }
0124 
0125 static const struct of_device_id ti_am335x_master_match[] __maybe_unused = {
0126     { .compatible = "ti,edma3-tpcc", },
0127     {},
0128 };
0129 
0130 static int ti_am335x_xbar_probe(struct platform_device *pdev)
0131 {
0132     struct device_node *node = pdev->dev.of_node;
0133     const struct of_device_id *match;
0134     struct device_node *dma_node;
0135     struct ti_am335x_xbar_data *xbar;
0136     void __iomem *iomem;
0137     int i, ret;
0138 
0139     if (!node)
0140         return -ENODEV;
0141 
0142     xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
0143     if (!xbar)
0144         return -ENOMEM;
0145 
0146     dma_node = of_parse_phandle(node, "dma-masters", 0);
0147     if (!dma_node) {
0148         dev_err(&pdev->dev, "Can't get DMA master node\n");
0149         return -ENODEV;
0150     }
0151 
0152     match = of_match_node(ti_am335x_master_match, dma_node);
0153     if (!match) {
0154         dev_err(&pdev->dev, "DMA master is not supported\n");
0155         of_node_put(dma_node);
0156         return -EINVAL;
0157     }
0158 
0159     if (of_property_read_u32(dma_node, "dma-requests",
0160                  &xbar->dma_requests)) {
0161         dev_info(&pdev->dev,
0162              "Missing XBAR output information, using %u.\n",
0163              TI_AM335X_XBAR_LINES);
0164         xbar->dma_requests = TI_AM335X_XBAR_LINES;
0165     }
0166     of_node_put(dma_node);
0167 
0168     if (of_property_read_u32(node, "dma-requests", &xbar->xbar_events)) {
0169         dev_info(&pdev->dev,
0170              "Missing XBAR input information, using %u.\n",
0171              TI_AM335X_XBAR_LINES);
0172         xbar->xbar_events = TI_AM335X_XBAR_LINES;
0173     }
0174 
0175     iomem = devm_platform_ioremap_resource(pdev, 0);
0176     if (IS_ERR(iomem))
0177         return PTR_ERR(iomem);
0178 
0179     xbar->iomem = iomem;
0180 
0181     xbar->dmarouter.dev = &pdev->dev;
0182     xbar->dmarouter.route_free = ti_am335x_xbar_free;
0183 
0184     platform_set_drvdata(pdev, xbar);
0185 
0186     /* Reset the crossbar */
0187     for (i = 0; i < xbar->dma_requests; i++)
0188         ti_am335x_xbar_write(xbar->iomem, i, 0);
0189 
0190     ret = of_dma_router_register(node, ti_am335x_xbar_route_allocate,
0191                      &xbar->dmarouter);
0192 
0193     return ret;
0194 }
0195 
0196 /* Crossbar on DRA7xx family */
0197 #define TI_DRA7_XBAR_OUTPUTS    127
0198 #define TI_DRA7_XBAR_INPUTS 256
0199 
0200 struct ti_dra7_xbar_data {
0201     void __iomem *iomem;
0202 
0203     struct dma_router dmarouter;
0204     struct mutex mutex;
0205     unsigned long *dma_inuse;
0206 
0207     u16 safe_val; /* Value to rest the crossbar lines */
0208     u32 xbar_requests; /* number of DMA requests connected to XBAR */
0209     u32 dma_requests; /* number of DMA requests forwarded to DMA */
0210     u32 dma_offset;
0211 };
0212 
0213 struct ti_dra7_xbar_map {
0214     u16 xbar_in;
0215     int xbar_out;
0216 };
0217 
0218 static inline void ti_dra7_xbar_write(void __iomem *iomem, int xbar, u16 val)
0219 {
0220     writew_relaxed(val, iomem + (xbar * 2));
0221 }
0222 
0223 static void ti_dra7_xbar_free(struct device *dev, void *route_data)
0224 {
0225     struct ti_dra7_xbar_data *xbar = dev_get_drvdata(dev);
0226     struct ti_dra7_xbar_map *map = route_data;
0227 
0228     dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n",
0229         map->xbar_in, map->xbar_out);
0230 
0231     ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
0232     mutex_lock(&xbar->mutex);
0233     clear_bit(map->xbar_out, xbar->dma_inuse);
0234     mutex_unlock(&xbar->mutex);
0235     kfree(map);
0236 }
0237 
0238 static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
0239                      struct of_dma *ofdma)
0240 {
0241     struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
0242     struct ti_dra7_xbar_data *xbar = platform_get_drvdata(pdev);
0243     struct ti_dra7_xbar_map *map;
0244 
0245     if (dma_spec->args[0] >= xbar->xbar_requests) {
0246         dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
0247             dma_spec->args[0]);
0248         put_device(&pdev->dev);
0249         return ERR_PTR(-EINVAL);
0250     }
0251 
0252     /* The of_node_put() will be done in the core for the node */
0253     dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
0254     if (!dma_spec->np) {
0255         dev_err(&pdev->dev, "Can't get DMA master\n");
0256         put_device(&pdev->dev);
0257         return ERR_PTR(-EINVAL);
0258     }
0259 
0260     map = kzalloc(sizeof(*map), GFP_KERNEL);
0261     if (!map) {
0262         of_node_put(dma_spec->np);
0263         put_device(&pdev->dev);
0264         return ERR_PTR(-ENOMEM);
0265     }
0266 
0267     mutex_lock(&xbar->mutex);
0268     map->xbar_out = find_first_zero_bit(xbar->dma_inuse,
0269                         xbar->dma_requests);
0270     if (map->xbar_out == xbar->dma_requests) {
0271         mutex_unlock(&xbar->mutex);
0272         dev_err(&pdev->dev, "Run out of free DMA requests\n");
0273         kfree(map);
0274         of_node_put(dma_spec->np);
0275         put_device(&pdev->dev);
0276         return ERR_PTR(-ENOMEM);
0277     }
0278     set_bit(map->xbar_out, xbar->dma_inuse);
0279     mutex_unlock(&xbar->mutex);
0280 
0281     map->xbar_in = (u16)dma_spec->args[0];
0282 
0283     dma_spec->args[0] = map->xbar_out + xbar->dma_offset;
0284 
0285     dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n",
0286         map->xbar_in, map->xbar_out);
0287 
0288     ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
0289 
0290     return map;
0291 }
0292 
0293 #define TI_XBAR_EDMA_OFFSET 0
0294 #define TI_XBAR_SDMA_OFFSET 1
0295 static const u32 ti_dma_offset[] = {
0296     [TI_XBAR_EDMA_OFFSET] = 0,
0297     [TI_XBAR_SDMA_OFFSET] = 1,
0298 };
0299 
0300 static const struct of_device_id ti_dra7_master_match[] __maybe_unused = {
0301     {
0302         .compatible = "ti,omap4430-sdma",
0303         .data = &ti_dma_offset[TI_XBAR_SDMA_OFFSET],
0304     },
0305     {
0306         .compatible = "ti,edma3",
0307         .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
0308     },
0309     {
0310         .compatible = "ti,edma3-tpcc",
0311         .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
0312     },
0313     {},
0314 };
0315 
0316 static inline void ti_dra7_xbar_reserve(int offset, int len, unsigned long *p)
0317 {
0318     for (; len > 0; len--)
0319         set_bit(offset + (len - 1), p);
0320 }
0321 
0322 static int ti_dra7_xbar_probe(struct platform_device *pdev)
0323 {
0324     struct device_node *node = pdev->dev.of_node;
0325     const struct of_device_id *match;
0326     struct device_node *dma_node;
0327     struct ti_dra7_xbar_data *xbar;
0328     struct property *prop;
0329     u32 safe_val;
0330     int sz;
0331     void __iomem *iomem;
0332     int i, ret;
0333 
0334     if (!node)
0335         return -ENODEV;
0336 
0337     xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
0338     if (!xbar)
0339         return -ENOMEM;
0340 
0341     dma_node = of_parse_phandle(node, "dma-masters", 0);
0342     if (!dma_node) {
0343         dev_err(&pdev->dev, "Can't get DMA master node\n");
0344         return -ENODEV;
0345     }
0346 
0347     match = of_match_node(ti_dra7_master_match, dma_node);
0348     if (!match) {
0349         dev_err(&pdev->dev, "DMA master is not supported\n");
0350         of_node_put(dma_node);
0351         return -EINVAL;
0352     }
0353 
0354     if (of_property_read_u32(dma_node, "dma-requests",
0355                  &xbar->dma_requests)) {
0356         dev_info(&pdev->dev,
0357              "Missing XBAR output information, using %u.\n",
0358              TI_DRA7_XBAR_OUTPUTS);
0359         xbar->dma_requests = TI_DRA7_XBAR_OUTPUTS;
0360     }
0361     of_node_put(dma_node);
0362 
0363     xbar->dma_inuse = devm_kcalloc(&pdev->dev,
0364                        BITS_TO_LONGS(xbar->dma_requests),
0365                        sizeof(unsigned long), GFP_KERNEL);
0366     if (!xbar->dma_inuse)
0367         return -ENOMEM;
0368 
0369     if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
0370         dev_info(&pdev->dev,
0371              "Missing XBAR input information, using %u.\n",
0372              TI_DRA7_XBAR_INPUTS);
0373         xbar->xbar_requests = TI_DRA7_XBAR_INPUTS;
0374     }
0375 
0376     if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
0377         xbar->safe_val = (u16)safe_val;
0378 
0379 
0380     prop = of_find_property(node, "ti,reserved-dma-request-ranges", &sz);
0381     if (prop) {
0382         const char pname[] = "ti,reserved-dma-request-ranges";
0383         u32 (*rsv_events)[2];
0384         size_t nelm = sz / sizeof(*rsv_events);
0385         int i;
0386 
0387         if (!nelm)
0388             return -EINVAL;
0389 
0390         rsv_events = kcalloc(nelm, sizeof(*rsv_events), GFP_KERNEL);
0391         if (!rsv_events)
0392             return -ENOMEM;
0393 
0394         ret = of_property_read_u32_array(node, pname, (u32 *)rsv_events,
0395                          nelm * 2);
0396         if (ret) {
0397             kfree(rsv_events);
0398             return ret;
0399         }
0400 
0401         for (i = 0; i < nelm; i++) {
0402             ti_dra7_xbar_reserve(rsv_events[i][0], rsv_events[i][1],
0403                          xbar->dma_inuse);
0404         }
0405         kfree(rsv_events);
0406     }
0407 
0408     iomem = devm_platform_ioremap_resource(pdev, 0);
0409     if (IS_ERR(iomem))
0410         return PTR_ERR(iomem);
0411 
0412     xbar->iomem = iomem;
0413 
0414     xbar->dmarouter.dev = &pdev->dev;
0415     xbar->dmarouter.route_free = ti_dra7_xbar_free;
0416     xbar->dma_offset = *(u32 *)match->data;
0417 
0418     mutex_init(&xbar->mutex);
0419     platform_set_drvdata(pdev, xbar);
0420 
0421     /* Reset the crossbar */
0422     for (i = 0; i < xbar->dma_requests; i++) {
0423         if (!test_bit(i, xbar->dma_inuse))
0424             ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val);
0425     }
0426 
0427     ret = of_dma_router_register(node, ti_dra7_xbar_route_allocate,
0428                      &xbar->dmarouter);
0429     if (ret) {
0430         /* Restore the defaults for the crossbar */
0431         for (i = 0; i < xbar->dma_requests; i++) {
0432             if (!test_bit(i, xbar->dma_inuse))
0433                 ti_dra7_xbar_write(xbar->iomem, i, i);
0434         }
0435     }
0436 
0437     return ret;
0438 }
0439 
0440 static int ti_dma_xbar_probe(struct platform_device *pdev)
0441 {
0442     const struct of_device_id *match;
0443     int ret;
0444 
0445     match = of_match_node(ti_dma_xbar_match, pdev->dev.of_node);
0446     if (unlikely(!match))
0447         return -EINVAL;
0448 
0449     switch (*(u32 *)match->data) {
0450     case TI_XBAR_DRA7:
0451         ret = ti_dra7_xbar_probe(pdev);
0452         break;
0453     case TI_XBAR_AM335X:
0454         ret = ti_am335x_xbar_probe(pdev);
0455         break;
0456     default:
0457         dev_err(&pdev->dev, "Unsupported crossbar\n");
0458         ret = -ENODEV;
0459         break;
0460     }
0461 
0462     return ret;
0463 }
0464 
0465 static struct platform_driver ti_dma_xbar_driver = {
0466     .driver = {
0467         .name = "ti-dma-crossbar",
0468         .of_match_table = ti_dma_xbar_match,
0469     },
0470     .probe  = ti_dma_xbar_probe,
0471 };
0472 
0473 static int omap_dmaxbar_init(void)
0474 {
0475     return platform_driver_register(&ti_dma_xbar_driver);
0476 }
0477 arch_initcall(omap_dmaxbar_init);