aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTimur Tabi <timur@freescale.com>2008-09-26 20:00:11 -0400
committerDan Williams <dan.j.williams@intel.com>2008-09-26 20:00:11 -0400
commit77cd62e8082b9743b59ee1946a4c3ee2e3cd2bce (patch)
tree8fe08914499988f47f51e74395522e5862b0c31d /drivers
parent59f647c25a4f27c1e5c84710e0608b36303089f9 (diff)
fsldma: allow Freescale Elo DMA driver to be compiled as a module
Modify the Freescale Elo / Elo Plus DMA driver so that it can be compiled as a module. The primary change is to stop treating the DMA controller as a bus, and the DMA channels as devices on the bus. This is because the Open Firmware (OF) kernel code does not allow busses to be removed, so although we can call of_platform_bus_probe() to probe the DMA channels, there is no of_platform_bus_remove(). Instead, the DMA channels are manually probed, similar to what fsl_elbc_nand.c does. Cc: Scott Wood <scottwood@freescale.com> Acked-by: Li Yang <leoli@freescale.com> Signed-off-by: Timur Tabi <timur@freescale.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/Kconfig10
-rw-r--r--drivers/dma/fsldma.c138
-rw-r--r--drivers/dma/fsldma.h1
3 files changed, 94 insertions, 55 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index cd303901eb5b..904e57558bb5 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -48,13 +48,13 @@ config DW_DMAC
48 can be integrated in chips such as the Atmel AT32ap7000. 48 can be integrated in chips such as the Atmel AT32ap7000.
49 49
50config FSL_DMA 50config FSL_DMA
51 bool "Freescale MPC85xx/MPC83xx DMA support" 51 tristate "Freescale Elo and Elo Plus DMA support"
52 depends on PPC 52 depends on FSL_SOC
53 select DMA_ENGINE 53 select DMA_ENGINE
54 ---help--- 54 ---help---
55 Enable support for the Freescale DMA engine. Now, it support 55 Enable support for the Freescale Elo and Elo Plus DMA controllers.
56 MPC8560/40, MPC8555, MPC8548 and MPC8641 processors. 56 The Elo is the DMA controller on some 82xx and 83xx parts, and the
57 The MPC8349, MPC8360 is also supported. 57 Elo Plus is the DMA controller on 85xx and 86xx parts.
58 58
59config MV_XOR 59config MV_XOR
60 bool "Marvell XOR engine support" 60 bool "Marvell XOR engine support"
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index e9b263897c03..0b95dcce447e 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -370,7 +370,10 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *chan,
370 struct dma_client *client) 370 struct dma_client *client)
371{ 371{
372 struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); 372 struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
373 LIST_HEAD(tmp_list); 373
374 /* Has this channel already been allocated? */
375 if (fsl_chan->desc_pool)
376 return 1;
374 377
375 /* We need the descriptor to be aligned to 32bytes 378 /* We need the descriptor to be aligned to 32bytes
376 * for meeting FSL DMA specification requirement. 379 * for meeting FSL DMA specification requirement.
@@ -410,6 +413,8 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan)
410 } 413 }
411 spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); 414 spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
412 dma_pool_destroy(fsl_chan->desc_pool); 415 dma_pool_destroy(fsl_chan->desc_pool);
416
417 fsl_chan->desc_pool = NULL;
413} 418}
414 419
415static struct dma_async_tx_descriptor * 420static struct dma_async_tx_descriptor *
@@ -786,33 +791,29 @@ static void dma_do_tasklet(unsigned long data)
786 fsl_chan_ld_cleanup(fsl_chan); 791 fsl_chan_ld_cleanup(fsl_chan);
787} 792}
788 793
789static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, 794static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
790 const struct of_device_id *match) 795 struct device_node *node, u32 feature, const char *compatible)
791{ 796{
792 struct fsl_dma_device *fdev;
793 struct fsl_dma_chan *new_fsl_chan; 797 struct fsl_dma_chan *new_fsl_chan;
794 int err; 798 int err;
795 799
796 fdev = dev_get_drvdata(dev->dev.parent);
797 BUG_ON(!fdev);
798
799 /* alloc channel */ 800 /* alloc channel */
800 new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL); 801 new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL);
801 if (!new_fsl_chan) { 802 if (!new_fsl_chan) {
802 dev_err(&dev->dev, "No free memory for allocating " 803 dev_err(fdev->dev, "No free memory for allocating "
803 "dma channels!\n"); 804 "dma channels!\n");
804 return -ENOMEM; 805 return -ENOMEM;
805 } 806 }
806 807
807 /* get dma channel register base */ 808 /* get dma channel register base */
808 err = of_address_to_resource(dev->node, 0, &new_fsl_chan->reg); 809 err = of_address_to_resource(node, 0, &new_fsl_chan->reg);
809 if (err) { 810 if (err) {
810 dev_err(&dev->dev, "Can't get %s property 'reg'\n", 811 dev_err(fdev->dev, "Can't get %s property 'reg'\n",
811 dev->node->full_name); 812 node->full_name);
812 goto err_no_reg; 813 goto err_no_reg;
813 } 814 }
814 815
815 new_fsl_chan->feature = *(u32 *)match->data; 816 new_fsl_chan->feature = feature;
816 817
817 if (!fdev->feature) 818 if (!fdev->feature)
818 fdev->feature = new_fsl_chan->feature; 819 fdev->feature = new_fsl_chan->feature;
@@ -822,13 +823,13 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev,
822 */ 823 */
823 WARN_ON(fdev->feature != new_fsl_chan->feature); 824 WARN_ON(fdev->feature != new_fsl_chan->feature);
824 825
825 new_fsl_chan->dev = &dev->dev; 826 new_fsl_chan->dev = &new_fsl_chan->common.dev;
826 new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start, 827 new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start,
827 new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1); 828 new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1);
828 829
829 new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7; 830 new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7;
830 if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) { 831 if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) {
831 dev_err(&dev->dev, "There is no %d channel!\n", 832 dev_err(fdev->dev, "There is no %d channel!\n",
832 new_fsl_chan->id); 833 new_fsl_chan->id);
833 err = -EINVAL; 834 err = -EINVAL;
834 goto err_no_chan; 835 goto err_no_chan;
@@ -862,20 +863,20 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev,
862 &fdev->common.channels); 863 &fdev->common.channels);
863 fdev->common.chancnt++; 864 fdev->common.chancnt++;
864 865
865 new_fsl_chan->irq = irq_of_parse_and_map(dev->node, 0); 866 new_fsl_chan->irq = irq_of_parse_and_map(node, 0);
866 if (new_fsl_chan->irq != NO_IRQ) { 867 if (new_fsl_chan->irq != NO_IRQ) {
867 err = request_irq(new_fsl_chan->irq, 868 err = request_irq(new_fsl_chan->irq,
868 &fsl_dma_chan_do_interrupt, IRQF_SHARED, 869 &fsl_dma_chan_do_interrupt, IRQF_SHARED,
869 "fsldma-channel", new_fsl_chan); 870 "fsldma-channel", new_fsl_chan);
870 if (err) { 871 if (err) {
871 dev_err(&dev->dev, "DMA channel %s request_irq error " 872 dev_err(fdev->dev, "DMA channel %s request_irq error "
872 "with return %d\n", dev->node->full_name, err); 873 "with return %d\n", node->full_name, err);
873 goto err_no_irq; 874 goto err_no_irq;
874 } 875 }
875 } 876 }
876 877
877 dev_info(&dev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id, 878 dev_info(fdev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id,
878 match->compatible, new_fsl_chan->irq); 879 compatible, new_fsl_chan->irq);
879 880
880 return 0; 881 return 0;
881 882
@@ -888,38 +889,20 @@ err_no_reg:
888 return err; 889 return err;
889} 890}
890 891
891const u32 mpc8540_dma_ip_feature = FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN; 892static void fsl_dma_chan_remove(struct fsl_dma_chan *fchan)
892const u32 mpc8349_dma_ip_feature = FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN;
893
894static struct of_device_id of_fsl_dma_chan_ids[] = {
895 {
896 .compatible = "fsl,eloplus-dma-channel",
897 .data = (void *)&mpc8540_dma_ip_feature,
898 },
899 {
900 .compatible = "fsl,elo-dma-channel",
901 .data = (void *)&mpc8349_dma_ip_feature,
902 },
903 {}
904};
905
906static struct of_platform_driver of_fsl_dma_chan_driver = {
907 .name = "of-fsl-dma-channel",
908 .match_table = of_fsl_dma_chan_ids,
909 .probe = of_fsl_dma_chan_probe,
910};
911
912static __init int of_fsl_dma_chan_init(void)
913{ 893{
914 return of_register_platform_driver(&of_fsl_dma_chan_driver); 894 free_irq(fchan->irq, fchan);
895 list_del(&fchan->common.device_node);
896 iounmap(fchan->reg_base);
897 kfree(fchan);
915} 898}
916 899
917static int __devinit of_fsl_dma_probe(struct of_device *dev, 900static int __devinit of_fsl_dma_probe(struct of_device *dev,
918 const struct of_device_id *match) 901 const struct of_device_id *match)
919{ 902{
920 int err; 903 int err;
921 unsigned int irq;
922 struct fsl_dma_device *fdev; 904 struct fsl_dma_device *fdev;
905 struct device_node *child;
923 906
924 fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL); 907 fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL);
925 if (!fdev) { 908 if (!fdev) {
@@ -953,9 +936,9 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
953 fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; 936 fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
954 fdev->common.dev = &dev->dev; 937 fdev->common.dev = &dev->dev;
955 938
956 irq = irq_of_parse_and_map(dev->node, 0); 939 fdev->irq = irq_of_parse_and_map(dev->node, 0);
957 if (irq != NO_IRQ) { 940 if (fdev->irq != NO_IRQ) {
958 err = request_irq(irq, &fsl_dma_do_interrupt, IRQF_SHARED, 941 err = request_irq(fdev->irq, &fsl_dma_do_interrupt, IRQF_SHARED,
959 "fsldma-device", fdev); 942 "fsldma-device", fdev);
960 if (err) { 943 if (err) {
961 dev_err(&dev->dev, "DMA device request_irq error " 944 dev_err(&dev->dev, "DMA device request_irq error "
@@ -965,7 +948,21 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
965 } 948 }
966 949
967 dev_set_drvdata(&(dev->dev), fdev); 950 dev_set_drvdata(&(dev->dev), fdev);
968 of_platform_bus_probe(dev->node, of_fsl_dma_chan_ids, &dev->dev); 951
952 /* We cannot use of_platform_bus_probe() because there is no
953 * of_platform_bus_remove. Instead, we manually instantiate every DMA
954 * channel object.
955 */
956 for_each_child_of_node(dev->node, child) {
957 if (of_device_is_compatible(child, "fsl,eloplus-dma-channel"))
958 fsl_dma_chan_probe(fdev, child,
959 FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN,
960 "fsl,eloplus-dma-channel");
961 if (of_device_is_compatible(child, "fsl,elo-dma-channel"))
962 fsl_dma_chan_probe(fdev, child,
963 FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN,
964 "fsl,elo-dma-channel");
965 }
969 966
970 dma_async_device_register(&fdev->common); 967 dma_async_device_register(&fdev->common);
971 return 0; 968 return 0;
@@ -977,6 +974,30 @@ err_no_reg:
977 return err; 974 return err;
978} 975}
979 976
977static int of_fsl_dma_remove(struct of_device *of_dev)
978{
979 struct fsl_dma_device *fdev;
980 unsigned int i;
981
982 fdev = dev_get_drvdata(&of_dev->dev);
983
984 dma_async_device_unregister(&fdev->common);
985
986 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++)
987 if (fdev->chan[i])
988 fsl_dma_chan_remove(fdev->chan[i]);
989
990 if (fdev->irq != NO_IRQ)
991 free_irq(fdev->irq, fdev);
992
993 iounmap(fdev->reg_base);
994
995 kfree(fdev);
996 dev_set_drvdata(&of_dev->dev, NULL);
997
998 return 0;
999}
1000
980static struct of_device_id of_fsl_dma_ids[] = { 1001static struct of_device_id of_fsl_dma_ids[] = {
981 { .compatible = "fsl,eloplus-dma", }, 1002 { .compatible = "fsl,eloplus-dma", },
982 { .compatible = "fsl,elo-dma", }, 1003 { .compatible = "fsl,elo-dma", },
@@ -984,15 +1005,32 @@ static struct of_device_id of_fsl_dma_ids[] = {
984}; 1005};
985 1006
986static struct of_platform_driver of_fsl_dma_driver = { 1007static struct of_platform_driver of_fsl_dma_driver = {
987 .name = "of-fsl-dma", 1008 .name = "fsl-elo-dma",
988 .match_table = of_fsl_dma_ids, 1009 .match_table = of_fsl_dma_ids,
989 .probe = of_fsl_dma_probe, 1010 .probe = of_fsl_dma_probe,
1011 .remove = of_fsl_dma_remove,
990}; 1012};
991 1013
992static __init int of_fsl_dma_init(void) 1014static __init int of_fsl_dma_init(void)
993{ 1015{
994 return of_register_platform_driver(&of_fsl_dma_driver); 1016 int ret;
1017
1018 pr_info("Freescale Elo / Elo Plus DMA driver\n");
1019
1020 ret = of_register_platform_driver(&of_fsl_dma_driver);
1021 if (ret)
1022 pr_err("fsldma: failed to register platform driver\n");
1023
1024 return ret;
1025}
1026
1027static void __exit of_fsl_dma_exit(void)
1028{
1029 of_unregister_platform_driver(&of_fsl_dma_driver);
995} 1030}
996 1031
997subsys_initcall(of_fsl_dma_chan_init);
998subsys_initcall(of_fsl_dma_init); 1032subsys_initcall(of_fsl_dma_init);
1033module_exit(of_fsl_dma_exit);
1034
1035MODULE_DESCRIPTION("Freescale Elo / Elo Plus DMA driver");
1036MODULE_LICENSE("GPL");
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 6faf07ba0d0e..4f21a512d848 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -114,6 +114,7 @@ struct fsl_dma_device {
114 struct dma_device common; 114 struct dma_device common;
115 struct fsl_dma_chan *chan[FSL_DMA_MAX_CHANS_PER_DEVICE]; 115 struct fsl_dma_chan *chan[FSL_DMA_MAX_CHANS_PER_DEVICE];
116 u32 feature; /* The same as DMA channels */ 116 u32 feature; /* The same as DMA channels */
117 int irq; /* Channel IRQ */
117}; 118};
118 119
119/* Define macros for fsl_dma_chan->feature property */ 120/* Define macros for fsl_dma_chan->feature property */