diff options
-rw-r--r-- | drivers/dma/dma-jz4780.c | 61 |
1 files changed, 54 insertions, 7 deletions
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 7683de9fb9ee..184d1a2bf9ba 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c | |||
@@ -29,6 +29,9 @@ | |||
29 | #define JZ_DMA_REG_DIRQP 0x04 | 29 | #define JZ_DMA_REG_DIRQP 0x04 |
30 | #define JZ_DMA_REG_DDR 0x08 | 30 | #define JZ_DMA_REG_DDR 0x08 |
31 | #define JZ_DMA_REG_DDRS 0x0c | 31 | #define JZ_DMA_REG_DDRS 0x0c |
32 | #define JZ_DMA_REG_DCKE 0x10 | ||
33 | #define JZ_DMA_REG_DCKES 0x14 | ||
34 | #define JZ_DMA_REG_DCKEC 0x18 | ||
32 | #define JZ_DMA_REG_DMACP 0x1c | 35 | #define JZ_DMA_REG_DMACP 0x1c |
33 | #define JZ_DMA_REG_DSIRQP 0x20 | 36 | #define JZ_DMA_REG_DSIRQP 0x20 |
34 | #define JZ_DMA_REG_DSIRQM 0x24 | 37 | #define JZ_DMA_REG_DSIRQM 0x24 |
@@ -87,6 +90,11 @@ | |||
87 | 90 | ||
88 | #define JZ4780_DMA_CTRL_OFFSET 0x1000 | 91 | #define JZ4780_DMA_CTRL_OFFSET 0x1000 |
89 | 92 | ||
93 | /* macros for use with jz4780_dma_soc_data.flags */ | ||
94 | #define JZ_SOC_DATA_ALLOW_LEGACY_DT BIT(0) | ||
95 | #define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1) | ||
96 | #define JZ_SOC_DATA_PER_CHAN_PM BIT(2) | ||
97 | |||
90 | /** | 98 | /** |
91 | * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. | 99 | * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. |
92 | * @dcm: value for the DCM (channel command) register | 100 | * @dcm: value for the DCM (channel command) register |
@@ -133,6 +141,8 @@ struct jz4780_dma_chan { | |||
133 | 141 | ||
134 | struct jz4780_dma_soc_data { | 142 | struct jz4780_dma_soc_data { |
135 | unsigned int nb_channels; | 143 | unsigned int nb_channels; |
144 | unsigned int transfer_ord_max; | ||
145 | unsigned long flags; | ||
136 | }; | 146 | }; |
137 | 147 | ||
138 | struct jz4780_dma_dev { | 148 | struct jz4780_dma_dev { |
@@ -195,6 +205,20 @@ static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma, | |||
195 | writel(val, jzdma->ctrl_base + reg); | 205 | writel(val, jzdma->ctrl_base + reg); |
196 | } | 206 | } |
197 | 207 | ||
208 | static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma, | ||
209 | unsigned int chn) | ||
210 | { | ||
211 | if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) | ||
212 | jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKES, BIT(chn)); | ||
213 | } | ||
214 | |||
215 | static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma, | ||
216 | unsigned int chn) | ||
217 | { | ||
218 | if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) | ||
219 | jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn)); | ||
220 | } | ||
221 | |||
198 | static struct jz4780_dma_desc *jz4780_dma_desc_alloc( | 222 | static struct jz4780_dma_desc *jz4780_dma_desc_alloc( |
199 | struct jz4780_dma_chan *jzchan, unsigned int count, | 223 | struct jz4780_dma_chan *jzchan, unsigned int count, |
200 | enum dma_transaction_type type) | 224 | enum dma_transaction_type type) |
@@ -229,8 +253,10 @@ static void jz4780_dma_desc_free(struct virt_dma_desc *vdesc) | |||
229 | kfree(desc); | 253 | kfree(desc); |
230 | } | 254 | } |
231 | 255 | ||
232 | static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift) | 256 | static uint32_t jz4780_dma_transfer_size(struct jz4780_dma_chan *jzchan, |
257 | unsigned long val, uint32_t *shift) | ||
233 | { | 258 | { |
259 | struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); | ||
234 | int ord = ffs(val) - 1; | 260 | int ord = ffs(val) - 1; |
235 | 261 | ||
236 | /* | 262 | /* |
@@ -242,8 +268,8 @@ static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift) | |||
242 | */ | 268 | */ |
243 | if (ord == 3) | 269 | if (ord == 3) |
244 | ord = 2; | 270 | ord = 2; |
245 | else if (ord > 7) | 271 | else if (ord > jzdma->soc_data->transfer_ord_max) |
246 | ord = 7; | 272 | ord = jzdma->soc_data->transfer_ord_max; |
247 | 273 | ||
248 | *shift = ord; | 274 | *shift = ord; |
249 | 275 | ||
@@ -295,7 +321,7 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan, | |||
295 | * divisible by the transfer size, and we must not use more than the | 321 | * divisible by the transfer size, and we must not use more than the |
296 | * maximum burst specified by the user. | 322 | * maximum burst specified by the user. |
297 | */ | 323 | */ |
298 | tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst), | 324 | tsz = jz4780_dma_transfer_size(jzchan, addr | len | (width * maxburst), |
299 | &jzchan->transfer_shift); | 325 | &jzchan->transfer_shift); |
300 | 326 | ||
301 | switch (width) { | 327 | switch (width) { |
@@ -424,7 +450,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy( | |||
424 | if (!desc) | 450 | if (!desc) |
425 | return NULL; | 451 | return NULL; |
426 | 452 | ||
427 | tsz = jz4780_dma_transfer_size(dest | src | len, | 453 | tsz = jz4780_dma_transfer_size(jzchan, dest | src | len, |
428 | &jzchan->transfer_shift); | 454 | &jzchan->transfer_shift); |
429 | 455 | ||
430 | jzchan->transfer_type = JZ_DMA_DRT_AUTO; | 456 | jzchan->transfer_type = JZ_DMA_DRT_AUTO; |
@@ -485,6 +511,9 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan) | |||
485 | (jzchan->curr_hwdesc + 1) % jzchan->desc->count; | 511 | (jzchan->curr_hwdesc + 1) % jzchan->desc->count; |
486 | } | 512 | } |
487 | 513 | ||
514 | /* Enable the channel's clock. */ | ||
515 | jz4780_dma_chan_enable(jzdma, jzchan->id); | ||
516 | |||
488 | /* Use 4-word descriptors. */ | 517 | /* Use 4-word descriptors. */ |
489 | jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); | 518 | jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); |
490 | 519 | ||
@@ -532,6 +561,8 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan) | |||
532 | jzchan->desc = NULL; | 561 | jzchan->desc = NULL; |
533 | } | 562 | } |
534 | 563 | ||
564 | jz4780_dma_chan_disable(jzdma, jzchan->id); | ||
565 | |||
535 | vchan_get_all_descriptors(&jzchan->vchan, &head); | 566 | vchan_get_all_descriptors(&jzchan->vchan, &head); |
536 | 567 | ||
537 | spin_unlock_irqrestore(&jzchan->vchan.lock, flags); | 568 | spin_unlock_irqrestore(&jzchan->vchan.lock, flags); |
@@ -543,8 +574,10 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan) | |||
543 | static void jz4780_dma_synchronize(struct dma_chan *chan) | 574 | static void jz4780_dma_synchronize(struct dma_chan *chan) |
544 | { | 575 | { |
545 | struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); | 576 | struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); |
577 | struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); | ||
546 | 578 | ||
547 | vchan_synchronize(&jzchan->vchan); | 579 | vchan_synchronize(&jzchan->vchan); |
580 | jz4780_dma_chan_disable(jzdma, jzchan->id); | ||
548 | } | 581 | } |
549 | 582 | ||
550 | static int jz4780_dma_config(struct dma_chan *chan, | 583 | static int jz4780_dma_config(struct dma_chan *chan, |
@@ -812,13 +845,16 @@ static int jz4780_dma_probe(struct platform_device *pdev) | |||
812 | jzdma->ctrl_base = devm_ioremap_resource(dev, res); | 845 | jzdma->ctrl_base = devm_ioremap_resource(dev, res); |
813 | if (IS_ERR(jzdma->ctrl_base)) | 846 | if (IS_ERR(jzdma->ctrl_base)) |
814 | return PTR_ERR(jzdma->ctrl_base); | 847 | return PTR_ERR(jzdma->ctrl_base); |
815 | } else { | 848 | } else if (soc_data->flags & JZ_SOC_DATA_ALLOW_LEGACY_DT) { |
816 | /* | 849 | /* |
817 | * On JZ4780, if the second memory resource was not supplied, | 850 | * On JZ4780, if the second memory resource was not supplied, |
818 | * assume we're using an old devicetree, and calculate the | 851 | * assume we're using an old devicetree, and calculate the |
819 | * offset to the control registers. | 852 | * offset to the control registers. |
820 | */ | 853 | */ |
821 | jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET; | 854 | jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET; |
855 | } else { | ||
856 | dev_err(dev, "failed to get I/O memory\n"); | ||
857 | return -EINVAL; | ||
822 | } | 858 | } |
823 | 859 | ||
824 | ret = platform_get_irq(pdev, 0); | 860 | ret = platform_get_irq(pdev, 0); |
@@ -879,7 +915,9 @@ static int jz4780_dma_probe(struct platform_device *pdev) | |||
879 | */ | 915 | */ |
880 | jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, | 916 | jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, |
881 | JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC); | 917 | JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC); |
882 | jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0); | 918 | |
919 | if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA) | ||
920 | jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0); | ||
883 | 921 | ||
884 | INIT_LIST_HEAD(&dd->channels); | 922 | INIT_LIST_HEAD(&dd->channels); |
885 | 923 | ||
@@ -935,11 +973,20 @@ static int jz4780_dma_remove(struct platform_device *pdev) | |||
935 | return 0; | 973 | return 0; |
936 | } | 974 | } |
937 | 975 | ||
976 | static const struct jz4780_dma_soc_data jz4770_dma_soc_data = { | ||
977 | .nb_channels = 6, | ||
978 | .transfer_ord_max = 6, | ||
979 | .flags = JZ_SOC_DATA_PER_CHAN_PM, | ||
980 | }; | ||
981 | |||
938 | static const struct jz4780_dma_soc_data jz4780_dma_soc_data = { | 982 | static const struct jz4780_dma_soc_data jz4780_dma_soc_data = { |
939 | .nb_channels = 32, | 983 | .nb_channels = 32, |
984 | .transfer_ord_max = 7, | ||
985 | .flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA, | ||
940 | }; | 986 | }; |
941 | 987 | ||
942 | static const struct of_device_id jz4780_dma_dt_match[] = { | 988 | static const struct of_device_id jz4780_dma_dt_match[] = { |
989 | { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data }, | ||
943 | { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data }, | 990 | { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data }, |
944 | {}, | 991 | {}, |
945 | }; | 992 | }; |