diff options
Diffstat (limited to 'drivers/dma/amba-pl08x.c')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 246 |
1 files changed, 124 insertions, 122 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index e6d7228b1479..196a7378d332 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c | |||
@@ -156,14 +156,10 @@ struct pl08x_driver_data { | |||
156 | #define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */ | 156 | #define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */ |
157 | #define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT) | 157 | #define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT) |
158 | 158 | ||
159 | /* Minimum period between work queue runs */ | ||
160 | #define PL08X_WQ_PERIODMIN 20 | ||
161 | |||
162 | /* Size (bytes) of each LLI buffer allocated for one transfer */ | 159 | /* Size (bytes) of each LLI buffer allocated for one transfer */ |
163 | # define PL08X_LLI_TSFR_SIZE 0x2000 | 160 | # define PL08X_LLI_TSFR_SIZE 0x2000 |
164 | 161 | ||
165 | /* Maximum times we call dma_pool_alloc on this pool without freeing */ | 162 | /* Maximum times we call dma_pool_alloc on this pool without freeing */ |
166 | #define PL08X_MAX_ALLOCS 0x40 | ||
167 | #define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli)) | 163 | #define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli)) |
168 | #define PL08X_ALIGN 8 | 164 | #define PL08X_ALIGN 8 |
169 | 165 | ||
@@ -495,10 +491,10 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, | |||
495 | 491 | ||
496 | struct pl08x_lli_build_data { | 492 | struct pl08x_lli_build_data { |
497 | struct pl08x_txd *txd; | 493 | struct pl08x_txd *txd; |
498 | struct pl08x_driver_data *pl08x; | ||
499 | struct pl08x_bus_data srcbus; | 494 | struct pl08x_bus_data srcbus; |
500 | struct pl08x_bus_data dstbus; | 495 | struct pl08x_bus_data dstbus; |
501 | size_t remainder; | 496 | size_t remainder; |
497 | u32 lli_bus; | ||
502 | }; | 498 | }; |
503 | 499 | ||
504 | /* | 500 | /* |
@@ -551,8 +547,7 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, | |||
551 | llis_va[num_llis].src = bd->srcbus.addr; | 547 | llis_va[num_llis].src = bd->srcbus.addr; |
552 | llis_va[num_llis].dst = bd->dstbus.addr; | 548 | llis_va[num_llis].dst = bd->dstbus.addr; |
553 | llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); | 549 | llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); |
554 | if (bd->pl08x->lli_buses & PL08X_AHB2) | 550 | llis_va[num_llis].lli |= bd->lli_bus; |
555 | llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; | ||
556 | 551 | ||
557 | if (cctl & PL080_CONTROL_SRC_INCR) | 552 | if (cctl & PL080_CONTROL_SRC_INCR) |
558 | bd->srcbus.addr += len; | 553 | bd->srcbus.addr += len; |
@@ -605,9 +600,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
605 | cctl = txd->cctl; | 600 | cctl = txd->cctl; |
606 | 601 | ||
607 | bd.txd = txd; | 602 | bd.txd = txd; |
608 | bd.pl08x = pl08x; | ||
609 | bd.srcbus.addr = txd->src_addr; | 603 | bd.srcbus.addr = txd->src_addr; |
610 | bd.dstbus.addr = txd->dst_addr; | 604 | bd.dstbus.addr = txd->dst_addr; |
605 | bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0; | ||
611 | 606 | ||
612 | /* Find maximum width of the source bus */ | 607 | /* Find maximum width of the source bus */ |
613 | bd.srcbus.maxwidth = | 608 | bd.srcbus.maxwidth = |
@@ -622,25 +617,15 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
622 | /* Set up the bus widths to the maximum */ | 617 | /* Set up the bus widths to the maximum */ |
623 | bd.srcbus.buswidth = bd.srcbus.maxwidth; | 618 | bd.srcbus.buswidth = bd.srcbus.maxwidth; |
624 | bd.dstbus.buswidth = bd.dstbus.maxwidth; | 619 | bd.dstbus.buswidth = bd.dstbus.maxwidth; |
625 | dev_vdbg(&pl08x->adev->dev, | ||
626 | "%s source bus is %d bytes wide, dest bus is %d bytes wide\n", | ||
627 | __func__, bd.srcbus.buswidth, bd.dstbus.buswidth); | ||
628 | |||
629 | 620 | ||
630 | /* | 621 | /* |
631 | * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) | 622 | * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) |
632 | */ | 623 | */ |
633 | max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * | 624 | max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * |
634 | PL080_CONTROL_TRANSFER_SIZE_MASK; | 625 | PL080_CONTROL_TRANSFER_SIZE_MASK; |
635 | dev_vdbg(&pl08x->adev->dev, | ||
636 | "%s max bytes per lli = %zu\n", | ||
637 | __func__, max_bytes_per_lli); | ||
638 | 626 | ||
639 | /* We need to count this down to zero */ | 627 | /* We need to count this down to zero */ |
640 | bd.remainder = txd->len; | 628 | bd.remainder = txd->len; |
641 | dev_vdbg(&pl08x->adev->dev, | ||
642 | "%s remainder = %zu\n", | ||
643 | __func__, bd.remainder); | ||
644 | 629 | ||
645 | /* | 630 | /* |
646 | * Choose bus to align to | 631 | * Choose bus to align to |
@@ -649,6 +634,16 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
649 | */ | 634 | */ |
650 | pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); | 635 | pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); |
651 | 636 | ||
637 | dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu llimax=%zu\n", | ||
638 | bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "", | ||
639 | bd.srcbus.buswidth, | ||
640 | bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "", | ||
641 | bd.dstbus.buswidth, | ||
642 | bd.remainder, max_bytes_per_lli); | ||
643 | dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n", | ||
644 | mbus == &bd.srcbus ? "src" : "dst", | ||
645 | sbus == &bd.srcbus ? "src" : "dst"); | ||
646 | |||
652 | if (txd->len < mbus->buswidth) { | 647 | if (txd->len < mbus->buswidth) { |
653 | /* Less than a bus width available - send as single bytes */ | 648 | /* Less than a bus width available - send as single bytes */ |
654 | while (bd.remainder) { | 649 | while (bd.remainder) { |
@@ -840,15 +835,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
840 | { | 835 | { |
841 | int i; | 836 | int i; |
842 | 837 | ||
838 | dev_vdbg(&pl08x->adev->dev, | ||
839 | "%-3s %-9s %-10s %-10s %-10s %s\n", | ||
840 | "lli", "", "csrc", "cdst", "clli", "cctl"); | ||
843 | for (i = 0; i < num_llis; i++) { | 841 | for (i = 0; i < num_llis; i++) { |
844 | dev_vdbg(&pl08x->adev->dev, | 842 | dev_vdbg(&pl08x->adev->dev, |
845 | "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n", | 843 | "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n", |
846 | i, | 844 | i, &llis_va[i], llis_va[i].src, |
847 | &llis_va[i], | 845 | llis_va[i].dst, llis_va[i].lli, llis_va[i].cctl |
848 | llis_va[i].src, | ||
849 | llis_va[i].dst, | ||
850 | llis_va[i].cctl, | ||
851 | llis_va[i].lli | ||
852 | ); | 846 | ); |
853 | } | 847 | } |
854 | } | 848 | } |
@@ -1054,64 +1048,105 @@ pl08x_dma_tx_status(struct dma_chan *chan, | |||
1054 | 1048 | ||
1055 | /* PrimeCell DMA extension */ | 1049 | /* PrimeCell DMA extension */ |
1056 | struct burst_table { | 1050 | struct burst_table { |
1057 | int burstwords; | 1051 | u32 burstwords; |
1058 | u32 reg; | 1052 | u32 reg; |
1059 | }; | 1053 | }; |
1060 | 1054 | ||
1061 | static const struct burst_table burst_sizes[] = { | 1055 | static const struct burst_table burst_sizes[] = { |
1062 | { | 1056 | { |
1063 | .burstwords = 256, | 1057 | .burstwords = 256, |
1064 | .reg = (PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1058 | .reg = PL080_BSIZE_256, |
1065 | (PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1066 | }, | 1059 | }, |
1067 | { | 1060 | { |
1068 | .burstwords = 128, | 1061 | .burstwords = 128, |
1069 | .reg = (PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1062 | .reg = PL080_BSIZE_128, |
1070 | (PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1071 | }, | 1063 | }, |
1072 | { | 1064 | { |
1073 | .burstwords = 64, | 1065 | .burstwords = 64, |
1074 | .reg = (PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1066 | .reg = PL080_BSIZE_64, |
1075 | (PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1076 | }, | 1067 | }, |
1077 | { | 1068 | { |
1078 | .burstwords = 32, | 1069 | .burstwords = 32, |
1079 | .reg = (PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1070 | .reg = PL080_BSIZE_32, |
1080 | (PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1081 | }, | 1071 | }, |
1082 | { | 1072 | { |
1083 | .burstwords = 16, | 1073 | .burstwords = 16, |
1084 | .reg = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1074 | .reg = PL080_BSIZE_16, |
1085 | (PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1086 | }, | 1075 | }, |
1087 | { | 1076 | { |
1088 | .burstwords = 8, | 1077 | .burstwords = 8, |
1089 | .reg = (PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1078 | .reg = PL080_BSIZE_8, |
1090 | (PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1091 | }, | 1079 | }, |
1092 | { | 1080 | { |
1093 | .burstwords = 4, | 1081 | .burstwords = 4, |
1094 | .reg = (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1082 | .reg = PL080_BSIZE_4, |
1095 | (PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1096 | }, | 1083 | }, |
1097 | { | 1084 | { |
1098 | .burstwords = 1, | 1085 | .burstwords = 0, |
1099 | .reg = (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1086 | .reg = PL080_BSIZE_1, |
1100 | (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT), | ||
1101 | }, | 1087 | }, |
1102 | }; | 1088 | }; |
1103 | 1089 | ||
1090 | /* | ||
1091 | * Given the source and destination available bus masks, select which | ||
1092 | * will be routed to each port. We try to have source and destination | ||
1093 | * on separate ports, but always respect the allowable settings. | ||
1094 | */ | ||
1095 | static u32 pl08x_select_bus(u8 src, u8 dst) | ||
1096 | { | ||
1097 | u32 cctl = 0; | ||
1098 | |||
1099 | if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) | ||
1100 | cctl |= PL080_CONTROL_DST_AHB2; | ||
1101 | if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) | ||
1102 | cctl |= PL080_CONTROL_SRC_AHB2; | ||
1103 | |||
1104 | return cctl; | ||
1105 | } | ||
1106 | |||
1107 | static u32 pl08x_cctl(u32 cctl) | ||
1108 | { | ||
1109 | cctl &= ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | | ||
1110 | PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | | ||
1111 | PL080_CONTROL_PROT_MASK); | ||
1112 | |||
1113 | /* Access the cell in privileged mode, non-bufferable, non-cacheable */ | ||
1114 | return cctl | PL080_CONTROL_PROT_SYS; | ||
1115 | } | ||
1116 | |||
1117 | static u32 pl08x_width(enum dma_slave_buswidth width) | ||
1118 | { | ||
1119 | switch (width) { | ||
1120 | case DMA_SLAVE_BUSWIDTH_1_BYTE: | ||
1121 | return PL080_WIDTH_8BIT; | ||
1122 | case DMA_SLAVE_BUSWIDTH_2_BYTES: | ||
1123 | return PL080_WIDTH_16BIT; | ||
1124 | case DMA_SLAVE_BUSWIDTH_4_BYTES: | ||
1125 | return PL080_WIDTH_32BIT; | ||
1126 | default: | ||
1127 | return ~0; | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | static u32 pl08x_burst(u32 maxburst) | ||
1132 | { | ||
1133 | int i; | ||
1134 | |||
1135 | for (i = 0; i < ARRAY_SIZE(burst_sizes); i++) | ||
1136 | if (burst_sizes[i].burstwords <= maxburst) | ||
1137 | break; | ||
1138 | |||
1139 | return burst_sizes[i].reg; | ||
1140 | } | ||
1141 | |||
1104 | static int dma_set_runtime_config(struct dma_chan *chan, | 1142 | static int dma_set_runtime_config(struct dma_chan *chan, |
1105 | struct dma_slave_config *config) | 1143 | struct dma_slave_config *config) |
1106 | { | 1144 | { |
1107 | struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); | 1145 | struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); |
1108 | struct pl08x_driver_data *pl08x = plchan->host; | 1146 | struct pl08x_driver_data *pl08x = plchan->host; |
1109 | struct pl08x_channel_data *cd = plchan->cd; | ||
1110 | enum dma_slave_buswidth addr_width; | 1147 | enum dma_slave_buswidth addr_width; |
1111 | dma_addr_t addr; | 1148 | u32 width, burst, maxburst; |
1112 | u32 maxburst; | ||
1113 | u32 cctl = 0; | 1149 | u32 cctl = 0; |
1114 | int i; | ||
1115 | 1150 | ||
1116 | if (!plchan->slave) | 1151 | if (!plchan->slave) |
1117 | return -EINVAL; | 1152 | return -EINVAL; |
@@ -1119,11 +1154,9 @@ static int dma_set_runtime_config(struct dma_chan *chan, | |||
1119 | /* Transfer direction */ | 1154 | /* Transfer direction */ |
1120 | plchan->runtime_direction = config->direction; | 1155 | plchan->runtime_direction = config->direction; |
1121 | if (config->direction == DMA_TO_DEVICE) { | 1156 | if (config->direction == DMA_TO_DEVICE) { |
1122 | addr = config->dst_addr; | ||
1123 | addr_width = config->dst_addr_width; | 1157 | addr_width = config->dst_addr_width; |
1124 | maxburst = config->dst_maxburst; | 1158 | maxburst = config->dst_maxburst; |
1125 | } else if (config->direction == DMA_FROM_DEVICE) { | 1159 | } else if (config->direction == DMA_FROM_DEVICE) { |
1126 | addr = config->src_addr; | ||
1127 | addr_width = config->src_addr_width; | 1160 | addr_width = config->src_addr_width; |
1128 | maxburst = config->src_maxburst; | 1161 | maxburst = config->src_maxburst; |
1129 | } else { | 1162 | } else { |
@@ -1132,46 +1165,40 @@ static int dma_set_runtime_config(struct dma_chan *chan, | |||
1132 | return -EINVAL; | 1165 | return -EINVAL; |
1133 | } | 1166 | } |
1134 | 1167 | ||
1135 | switch (addr_width) { | 1168 | width = pl08x_width(addr_width); |
1136 | case DMA_SLAVE_BUSWIDTH_1_BYTE: | 1169 | if (width == ~0) { |
1137 | cctl |= (PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT) | | ||
1138 | (PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT); | ||
1139 | break; | ||
1140 | case DMA_SLAVE_BUSWIDTH_2_BYTES: | ||
1141 | cctl |= (PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT) | | ||
1142 | (PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT); | ||
1143 | break; | ||
1144 | case DMA_SLAVE_BUSWIDTH_4_BYTES: | ||
1145 | cctl |= (PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT) | | ||
1146 | (PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT); | ||
1147 | break; | ||
1148 | default: | ||
1149 | dev_err(&pl08x->adev->dev, | 1170 | dev_err(&pl08x->adev->dev, |
1150 | "bad runtime_config: alien address width\n"); | 1171 | "bad runtime_config: alien address width\n"); |
1151 | return -EINVAL; | 1172 | return -EINVAL; |
1152 | } | 1173 | } |
1153 | 1174 | ||
1175 | cctl |= width << PL080_CONTROL_SWIDTH_SHIFT; | ||
1176 | cctl |= width << PL080_CONTROL_DWIDTH_SHIFT; | ||
1177 | |||
1154 | /* | 1178 | /* |
1155 | * Now decide on a maxburst: | ||
1156 | * If this channel will only request single transfers, set this | 1179 | * If this channel will only request single transfers, set this |
1157 | * down to ONE element. Also select one element if no maxburst | 1180 | * down to ONE element. Also select one element if no maxburst |
1158 | * is specified. | 1181 | * is specified. |
1159 | */ | 1182 | */ |
1160 | if (plchan->cd->single || maxburst == 0) { | 1183 | if (plchan->cd->single) |
1161 | cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) | | 1184 | maxburst = 1; |
1162 | (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT); | 1185 | |
1186 | burst = pl08x_burst(maxburst); | ||
1187 | cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT; | ||
1188 | cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT; | ||
1189 | |||
1190 | if (plchan->runtime_direction == DMA_FROM_DEVICE) { | ||
1191 | plchan->src_addr = config->src_addr; | ||
1192 | plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR | | ||
1193 | pl08x_select_bus(plchan->cd->periph_buses, | ||
1194 | pl08x->mem_buses); | ||
1163 | } else { | 1195 | } else { |
1164 | for (i = 0; i < ARRAY_SIZE(burst_sizes); i++) | 1196 | plchan->dst_addr = config->dst_addr; |
1165 | if (burst_sizes[i].burstwords <= maxburst) | 1197 | plchan->dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR | |
1166 | break; | 1198 | pl08x_select_bus(pl08x->mem_buses, |
1167 | cctl |= burst_sizes[i].reg; | 1199 | plchan->cd->periph_buses); |
1168 | } | 1200 | } |
1169 | 1201 | ||
1170 | plchan->runtime_addr = addr; | ||
1171 | |||
1172 | /* Modify the default channel data to fit PrimeCell request */ | ||
1173 | cd->cctl = cctl; | ||
1174 | |||
1175 | dev_dbg(&pl08x->adev->dev, | 1202 | dev_dbg(&pl08x->adev->dev, |
1176 | "configured channel %s (%s) for %s, data width %d, " | 1203 | "configured channel %s (%s) for %s, data width %d, " |
1177 | "maxburst %d words, LE, CCTL=0x%08x\n", | 1204 | "maxburst %d words, LE, CCTL=0x%08x\n", |
@@ -1270,23 +1297,6 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, | |||
1270 | return 0; | 1297 | return 0; |
1271 | } | 1298 | } |
1272 | 1299 | ||
1273 | /* | ||
1274 | * Given the source and destination available bus masks, select which | ||
1275 | * will be routed to each port. We try to have source and destination | ||
1276 | * on separate ports, but always respect the allowable settings. | ||
1277 | */ | ||
1278 | static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst) | ||
1279 | { | ||
1280 | u32 cctl = 0; | ||
1281 | |||
1282 | if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) | ||
1283 | cctl |= PL080_CONTROL_DST_AHB2; | ||
1284 | if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) | ||
1285 | cctl |= PL080_CONTROL_SRC_AHB2; | ||
1286 | |||
1287 | return cctl; | ||
1288 | } | ||
1289 | |||
1290 | static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, | 1300 | static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, |
1291 | unsigned long flags) | 1301 | unsigned long flags) |
1292 | { | 1302 | { |
@@ -1338,8 +1348,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( | |||
1338 | txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; | 1348 | txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; |
1339 | 1349 | ||
1340 | if (pl08x->vd->dualmaster) | 1350 | if (pl08x->vd->dualmaster) |
1341 | txd->cctl |= pl08x_select_bus(pl08x, | 1351 | txd->cctl |= pl08x_select_bus(pl08x->mem_buses, |
1342 | pl08x->mem_buses, pl08x->mem_buses); | 1352 | pl08x->mem_buses); |
1343 | 1353 | ||
1344 | ret = pl08x_prep_channel_resources(plchan, txd); | 1354 | ret = pl08x_prep_channel_resources(plchan, txd); |
1345 | if (ret) | 1355 | if (ret) |
@@ -1356,7 +1366,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( | |||
1356 | struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); | 1366 | struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); |
1357 | struct pl08x_driver_data *pl08x = plchan->host; | 1367 | struct pl08x_driver_data *pl08x = plchan->host; |
1358 | struct pl08x_txd *txd; | 1368 | struct pl08x_txd *txd; |
1359 | u8 src_buses, dst_buses; | ||
1360 | int ret; | 1369 | int ret; |
1361 | 1370 | ||
1362 | /* | 1371 | /* |
@@ -1390,42 +1399,22 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( | |||
1390 | txd->direction = direction; | 1399 | txd->direction = direction; |
1391 | txd->len = sgl->length; | 1400 | txd->len = sgl->length; |
1392 | 1401 | ||
1393 | txd->cctl = plchan->cd->cctl & | ||
1394 | ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | | ||
1395 | PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | | ||
1396 | PL080_CONTROL_PROT_MASK); | ||
1397 | |||
1398 | /* Access the cell in privileged mode, non-bufferable, non-cacheable */ | ||
1399 | txd->cctl |= PL080_CONTROL_PROT_SYS; | ||
1400 | |||
1401 | if (direction == DMA_TO_DEVICE) { | 1402 | if (direction == DMA_TO_DEVICE) { |
1402 | txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; | 1403 | txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; |
1403 | txd->cctl |= PL080_CONTROL_SRC_INCR; | 1404 | txd->cctl = plchan->dst_cctl; |
1404 | txd->src_addr = sgl->dma_address; | 1405 | txd->src_addr = sgl->dma_address; |
1405 | if (plchan->runtime_addr) | 1406 | txd->dst_addr = plchan->dst_addr; |
1406 | txd->dst_addr = plchan->runtime_addr; | ||
1407 | else | ||
1408 | txd->dst_addr = plchan->cd->addr; | ||
1409 | src_buses = pl08x->mem_buses; | ||
1410 | dst_buses = plchan->cd->periph_buses; | ||
1411 | } else if (direction == DMA_FROM_DEVICE) { | 1407 | } else if (direction == DMA_FROM_DEVICE) { |
1412 | txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; | 1408 | txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; |
1413 | txd->cctl |= PL080_CONTROL_DST_INCR; | 1409 | txd->cctl = plchan->src_cctl; |
1414 | if (plchan->runtime_addr) | 1410 | txd->src_addr = plchan->src_addr; |
1415 | txd->src_addr = plchan->runtime_addr; | ||
1416 | else | ||
1417 | txd->src_addr = plchan->cd->addr; | ||
1418 | txd->dst_addr = sgl->dma_address; | 1411 | txd->dst_addr = sgl->dma_address; |
1419 | src_buses = plchan->cd->periph_buses; | ||
1420 | dst_buses = pl08x->mem_buses; | ||
1421 | } else { | 1412 | } else { |
1422 | dev_err(&pl08x->adev->dev, | 1413 | dev_err(&pl08x->adev->dev, |
1423 | "%s direction unsupported\n", __func__); | 1414 | "%s direction unsupported\n", __func__); |
1424 | return NULL; | 1415 | return NULL; |
1425 | } | 1416 | } |
1426 | 1417 | ||
1427 | txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses); | ||
1428 | |||
1429 | ret = pl08x_prep_channel_resources(plchan, txd); | 1418 | ret = pl08x_prep_channel_resources(plchan, txd); |
1430 | if (ret) | 1419 | if (ret) |
1431 | return NULL; | 1420 | return NULL; |
@@ -1676,6 +1665,20 @@ static irqreturn_t pl08x_irq(int irq, void *dev) | |||
1676 | return mask ? IRQ_HANDLED : IRQ_NONE; | 1665 | return mask ? IRQ_HANDLED : IRQ_NONE; |
1677 | } | 1666 | } |
1678 | 1667 | ||
1668 | static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) | ||
1669 | { | ||
1670 | u32 cctl = pl08x_cctl(chan->cd->cctl); | ||
1671 | |||
1672 | chan->slave = true; | ||
1673 | chan->name = chan->cd->bus_id; | ||
1674 | chan->src_addr = chan->cd->addr; | ||
1675 | chan->dst_addr = chan->cd->addr; | ||
1676 | chan->src_cctl = cctl | PL080_CONTROL_DST_INCR | | ||
1677 | pl08x_select_bus(chan->cd->periph_buses, chan->host->mem_buses); | ||
1678 | chan->dst_cctl = cctl | PL080_CONTROL_SRC_INCR | | ||
1679 | pl08x_select_bus(chan->host->mem_buses, chan->cd->periph_buses); | ||
1680 | } | ||
1681 | |||
1679 | /* | 1682 | /* |
1680 | * Initialise the DMAC memcpy/slave channels. | 1683 | * Initialise the DMAC memcpy/slave channels. |
1681 | * Make a local wrapper to hold required data | 1684 | * Make a local wrapper to hold required data |
@@ -1707,9 +1710,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, | |||
1707 | chan->state = PL08X_CHAN_IDLE; | 1710 | chan->state = PL08X_CHAN_IDLE; |
1708 | 1711 | ||
1709 | if (slave) { | 1712 | if (slave) { |
1710 | chan->slave = true; | ||
1711 | chan->name = pl08x->pd->slave_channels[i].bus_id; | ||
1712 | chan->cd = &pl08x->pd->slave_channels[i]; | 1713 | chan->cd = &pl08x->pd->slave_channels[i]; |
1714 | pl08x_dma_slave_init(chan); | ||
1713 | } else { | 1715 | } else { |
1714 | chan->cd = &pl08x->pd->memcpy_channel; | 1716 | chan->cd = &pl08x->pd->memcpy_channel; |
1715 | chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i); | 1717 | chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i); |