diff options
author | Narayanan G <narayanan.gopalakrishnan@stericsson.com> | 2012-02-09 02:11:37 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@linux.intel.com> | 2012-04-23 08:26:17 -0400 |
commit | 1bdae6f49c52af3a58998cdb051dbd5b942f9273 (patch) | |
tree | 4b3ad9b496be8755fb3571593286b3144d364c7b /drivers | |
parent | ed8b0d67f33518a16c6b2450fe5ebebf180c2d04 (diff) |
dma40: Improve the logic of stopping logical chan
can be directly stopped by issuing a SUSPEND_REQ on the EE
bits. There is no need to suspend the physical channel and
restart it.
Also, the support for pre-V2 hw is discontinued.
EE bits for writing:
00: disable only if AS=11 or AS=00
01: enable
10: suspend_req only if AS=01 & EE=01 or EE=11
11: round / no change for writing
Signed-off-by: Narayanan G <narayanan.gopalakrishnan@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dma/ste_dma40.c | 320 | ||||
-rw-r--r-- | drivers/dma/ste_dma40_ll.h | 2 |
2 files changed, 199 insertions, 123 deletions
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index bdd41d4bfa8d..c5f26cc2c277 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c | |||
@@ -69,6 +69,22 @@ enum d40_command { | |||
69 | }; | 69 | }; |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * enum d40_events - The different Event Enables for the event lines. | ||
73 | * | ||
74 | * @D40_DEACTIVATE_EVENTLINE: De-activate Event line, stopping the logical chan. | ||
75 | * @D40_ACTIVATE_EVENTLINE: Activate the Event line, to start a logical chan. | ||
76 | * @D40_SUSPEND_REQ_EVENTLINE: Requesting for suspending a event line. | ||
77 | * @D40_ROUND_EVENTLINE: Status check for event line. | ||
78 | */ | ||
79 | |||
80 | enum d40_events { | ||
81 | D40_DEACTIVATE_EVENTLINE = 0, | ||
82 | D40_ACTIVATE_EVENTLINE = 1, | ||
83 | D40_SUSPEND_REQ_EVENTLINE = 2, | ||
84 | D40_ROUND_EVENTLINE = 3 | ||
85 | }; | ||
86 | |||
87 | /* | ||
72 | * These are the registers that has to be saved and later restored | 88 | * These are the registers that has to be saved and later restored |
73 | * when the DMA hw is powered off. | 89 | * when the DMA hw is powered off. |
74 | * TODO: Add save/restore of D40_DREG_GCC on dma40 v3 or later, if that works. | 90 | * TODO: Add save/restore of D40_DREG_GCC on dma40 v3 or later, if that works. |
@@ -870,8 +886,8 @@ static void d40_save_restore_registers(struct d40_base *base, bool save) | |||
870 | } | 886 | } |
871 | #endif | 887 | #endif |
872 | 888 | ||
873 | static int d40_channel_execute_command(struct d40_chan *d40c, | 889 | static int __d40_execute_command_phy(struct d40_chan *d40c, |
874 | enum d40_command command) | 890 | enum d40_command command) |
875 | { | 891 | { |
876 | u32 status; | 892 | u32 status; |
877 | int i; | 893 | int i; |
@@ -880,6 +896,12 @@ static int d40_channel_execute_command(struct d40_chan *d40c, | |||
880 | unsigned long flags; | 896 | unsigned long flags; |
881 | u32 wmask; | 897 | u32 wmask; |
882 | 898 | ||
899 | if (command == D40_DMA_STOP) { | ||
900 | ret = __d40_execute_command_phy(d40c, D40_DMA_SUSPEND_REQ); | ||
901 | if (ret) | ||
902 | return ret; | ||
903 | } | ||
904 | |||
883 | spin_lock_irqsave(&d40c->base->execmd_lock, flags); | 905 | spin_lock_irqsave(&d40c->base->execmd_lock, flags); |
884 | 906 | ||
885 | if (d40c->phy_chan->num % 2 == 0) | 907 | if (d40c->phy_chan->num % 2 == 0) |
@@ -973,67 +995,109 @@ static void d40_term_all(struct d40_chan *d40c) | |||
973 | } | 995 | } |
974 | 996 | ||
975 | d40c->pending_tx = 0; | 997 | d40c->pending_tx = 0; |
976 | d40c->busy = false; | ||
977 | } | 998 | } |
978 | 999 | ||
979 | static void __d40_config_set_event(struct d40_chan *d40c, bool enable, | 1000 | static void __d40_config_set_event(struct d40_chan *d40c, |
980 | u32 event, int reg) | 1001 | enum d40_events event_type, u32 event, |
1002 | int reg) | ||
981 | { | 1003 | { |
982 | void __iomem *addr = chan_base(d40c) + reg; | 1004 | void __iomem *addr = chan_base(d40c) + reg; |
983 | int tries; | 1005 | int tries; |
1006 | u32 status; | ||
1007 | |||
1008 | switch (event_type) { | ||
1009 | |||
1010 | case D40_DEACTIVATE_EVENTLINE: | ||
984 | 1011 | ||
985 | if (!enable) { | ||
986 | writel((D40_DEACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event)) | 1012 | writel((D40_DEACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event)) |
987 | | ~D40_EVENTLINE_MASK(event), addr); | 1013 | | ~D40_EVENTLINE_MASK(event), addr); |
988 | return; | 1014 | break; |
989 | } | 1015 | |
1016 | case D40_SUSPEND_REQ_EVENTLINE: | ||
1017 | status = (readl(addr) & D40_EVENTLINE_MASK(event)) >> | ||
1018 | D40_EVENTLINE_POS(event); | ||
1019 | |||
1020 | if (status == D40_DEACTIVATE_EVENTLINE || | ||
1021 | status == D40_SUSPEND_REQ_EVENTLINE) | ||
1022 | break; | ||
990 | 1023 | ||
1024 | writel((D40_SUSPEND_REQ_EVENTLINE << D40_EVENTLINE_POS(event)) | ||
1025 | | ~D40_EVENTLINE_MASK(event), addr); | ||
1026 | |||
1027 | for (tries = 0 ; tries < D40_SUSPEND_MAX_IT; tries++) { | ||
1028 | |||
1029 | status = (readl(addr) & D40_EVENTLINE_MASK(event)) >> | ||
1030 | D40_EVENTLINE_POS(event); | ||
1031 | |||
1032 | cpu_relax(); | ||
1033 | /* | ||
1034 | * Reduce the number of bus accesses while | ||
1035 | * waiting for the DMA to suspend. | ||
1036 | */ | ||
1037 | udelay(3); | ||
1038 | |||
1039 | if (status == D40_DEACTIVATE_EVENTLINE) | ||
1040 | break; | ||
1041 | } | ||
1042 | |||
1043 | if (tries == D40_SUSPEND_MAX_IT) { | ||
1044 | chan_err(d40c, | ||
1045 | "unable to stop the event_line chl %d (log: %d)" | ||
1046 | "status %x\n", d40c->phy_chan->num, | ||
1047 | d40c->log_num, status); | ||
1048 | } | ||
1049 | break; | ||
1050 | |||
1051 | case D40_ACTIVATE_EVENTLINE: | ||
991 | /* | 1052 | /* |
992 | * The hardware sometimes doesn't register the enable when src and dst | 1053 | * The hardware sometimes doesn't register the enable when src and dst |
993 | * event lines are active on the same logical channel. Retry to ensure | 1054 | * event lines are active on the same logical channel. Retry to ensure |
994 | * it does. Usually only one retry is sufficient. | 1055 | * it does. Usually only one retry is sufficient. |
995 | */ | 1056 | */ |
996 | tries = 100; | 1057 | tries = 100; |
997 | while (--tries) { | 1058 | while (--tries) { |
998 | writel((D40_ACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event)) | 1059 | writel((D40_ACTIVATE_EVENTLINE << |
999 | | ~D40_EVENTLINE_MASK(event), addr); | 1060 | D40_EVENTLINE_POS(event)) | |
1061 | ~D40_EVENTLINE_MASK(event), addr); | ||
1000 | 1062 | ||
1001 | if (readl(addr) & D40_EVENTLINE_MASK(event)) | 1063 | if (readl(addr) & D40_EVENTLINE_MASK(event)) |
1002 | break; | 1064 | break; |
1003 | } | 1065 | } |
1004 | 1066 | ||
1005 | if (tries != 99) | 1067 | if (tries != 99) |
1006 | dev_dbg(chan2dev(d40c), | 1068 | dev_dbg(chan2dev(d40c), |
1007 | "[%s] workaround enable S%cLNK (%d tries)\n", | 1069 | "[%s] workaround enable S%cLNK (%d tries)\n", |
1008 | __func__, reg == D40_CHAN_REG_SSLNK ? 'S' : 'D', | 1070 | __func__, reg == D40_CHAN_REG_SSLNK ? 'S' : 'D', |
1009 | 100 - tries); | 1071 | 100 - tries); |
1010 | 1072 | ||
1011 | WARN_ON(!tries); | 1073 | WARN_ON(!tries); |
1012 | } | 1074 | break; |
1013 | 1075 | ||
1014 | static void d40_config_set_event(struct d40_chan *d40c, bool do_enable) | 1076 | case D40_ROUND_EVENTLINE: |
1015 | { | 1077 | BUG(); |
1016 | unsigned long flags; | 1078 | break; |
1017 | 1079 | ||
1018 | spin_lock_irqsave(&d40c->phy_chan->lock, flags); | 1080 | } |
1081 | } | ||
1019 | 1082 | ||
1083 | static void d40_config_set_event(struct d40_chan *d40c, | ||
1084 | enum d40_events event_type) | ||
1085 | { | ||
1020 | /* Enable event line connected to device (or memcpy) */ | 1086 | /* Enable event line connected to device (or memcpy) */ |
1021 | if ((d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) || | 1087 | if ((d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) || |
1022 | (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH)) { | 1088 | (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH)) { |
1023 | u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type); | 1089 | u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type); |
1024 | 1090 | ||
1025 | __d40_config_set_event(d40c, do_enable, event, | 1091 | __d40_config_set_event(d40c, event_type, event, |
1026 | D40_CHAN_REG_SSLNK); | 1092 | D40_CHAN_REG_SSLNK); |
1027 | } | 1093 | } |
1028 | 1094 | ||
1029 | if (d40c->dma_cfg.dir != STEDMA40_PERIPH_TO_MEM) { | 1095 | if (d40c->dma_cfg.dir != STEDMA40_PERIPH_TO_MEM) { |
1030 | u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type); | 1096 | u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type); |
1031 | 1097 | ||
1032 | __d40_config_set_event(d40c, do_enable, event, | 1098 | __d40_config_set_event(d40c, event_type, event, |
1033 | D40_CHAN_REG_SDLNK); | 1099 | D40_CHAN_REG_SDLNK); |
1034 | } | 1100 | } |
1035 | |||
1036 | spin_unlock_irqrestore(&d40c->phy_chan->lock, flags); | ||
1037 | } | 1101 | } |
1038 | 1102 | ||
1039 | static u32 d40_chan_has_events(struct d40_chan *d40c) | 1103 | static u32 d40_chan_has_events(struct d40_chan *d40c) |
@@ -1047,6 +1111,64 @@ static u32 d40_chan_has_events(struct d40_chan *d40c) | |||
1047 | return val; | 1111 | return val; |
1048 | } | 1112 | } |
1049 | 1113 | ||
1114 | static int | ||
1115 | __d40_execute_command_log(struct d40_chan *d40c, enum d40_command command) | ||
1116 | { | ||
1117 | unsigned long flags; | ||
1118 | int ret = 0; | ||
1119 | u32 active_status; | ||
1120 | void __iomem *active_reg; | ||
1121 | |||
1122 | if (d40c->phy_chan->num % 2 == 0) | ||
1123 | active_reg = d40c->base->virtbase + D40_DREG_ACTIVE; | ||
1124 | else | ||
1125 | active_reg = d40c->base->virtbase + D40_DREG_ACTIVO; | ||
1126 | |||
1127 | |||
1128 | spin_lock_irqsave(&d40c->phy_chan->lock, flags); | ||
1129 | |||
1130 | switch (command) { | ||
1131 | case D40_DMA_STOP: | ||
1132 | case D40_DMA_SUSPEND_REQ: | ||
1133 | |||
1134 | active_status = (readl(active_reg) & | ||
1135 | D40_CHAN_POS_MASK(d40c->phy_chan->num)) >> | ||
1136 | D40_CHAN_POS(d40c->phy_chan->num); | ||
1137 | |||
1138 | if (active_status == D40_DMA_RUN) | ||
1139 | d40_config_set_event(d40c, D40_SUSPEND_REQ_EVENTLINE); | ||
1140 | else | ||
1141 | d40_config_set_event(d40c, D40_DEACTIVATE_EVENTLINE); | ||
1142 | |||
1143 | if (!d40_chan_has_events(d40c) && (command == D40_DMA_STOP)) | ||
1144 | ret = __d40_execute_command_phy(d40c, command); | ||
1145 | |||
1146 | break; | ||
1147 | |||
1148 | case D40_DMA_RUN: | ||
1149 | |||
1150 | d40_config_set_event(d40c, D40_ACTIVATE_EVENTLINE); | ||
1151 | ret = __d40_execute_command_phy(d40c, command); | ||
1152 | break; | ||
1153 | |||
1154 | case D40_DMA_SUSPENDED: | ||
1155 | BUG(); | ||
1156 | break; | ||
1157 | } | ||
1158 | |||
1159 | spin_unlock_irqrestore(&d40c->phy_chan->lock, flags); | ||
1160 | return ret; | ||
1161 | } | ||
1162 | |||
1163 | static int d40_channel_execute_command(struct d40_chan *d40c, | ||
1164 | enum d40_command command) | ||
1165 | { | ||
1166 | if (chan_is_logical(d40c)) | ||
1167 | return __d40_execute_command_log(d40c, command); | ||
1168 | else | ||
1169 | return __d40_execute_command_phy(d40c, command); | ||
1170 | } | ||
1171 | |||
1050 | static u32 d40_get_prmo(struct d40_chan *d40c) | 1172 | static u32 d40_get_prmo(struct d40_chan *d40c) |
1051 | { | 1173 | { |
1052 | static const unsigned int phy_map[] = { | 1174 | static const unsigned int phy_map[] = { |
@@ -1149,15 +1271,7 @@ static int d40_pause(struct d40_chan *d40c) | |||
1149 | spin_lock_irqsave(&d40c->lock, flags); | 1271 | spin_lock_irqsave(&d40c->lock, flags); |
1150 | 1272 | ||
1151 | res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); | 1273 | res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); |
1152 | if (res == 0) { | 1274 | |
1153 | if (chan_is_logical(d40c)) { | ||
1154 | d40_config_set_event(d40c, false); | ||
1155 | /* Resume the other logical channels if any */ | ||
1156 | if (d40_chan_has_events(d40c)) | ||
1157 | res = d40_channel_execute_command(d40c, | ||
1158 | D40_DMA_RUN); | ||
1159 | } | ||
1160 | } | ||
1161 | pm_runtime_mark_last_busy(d40c->base->dev); | 1275 | pm_runtime_mark_last_busy(d40c->base->dev); |
1162 | pm_runtime_put_autosuspend(d40c->base->dev); | 1276 | pm_runtime_put_autosuspend(d40c->base->dev); |
1163 | spin_unlock_irqrestore(&d40c->lock, flags); | 1277 | spin_unlock_irqrestore(&d40c->lock, flags); |
@@ -1174,45 +1288,17 @@ static int d40_resume(struct d40_chan *d40c) | |||
1174 | 1288 | ||
1175 | spin_lock_irqsave(&d40c->lock, flags); | 1289 | spin_lock_irqsave(&d40c->lock, flags); |
1176 | pm_runtime_get_sync(d40c->base->dev); | 1290 | pm_runtime_get_sync(d40c->base->dev); |
1177 | if (d40c->base->rev == 0) | ||
1178 | if (chan_is_logical(d40c)) { | ||
1179 | res = d40_channel_execute_command(d40c, | ||
1180 | D40_DMA_SUSPEND_REQ); | ||
1181 | goto no_suspend; | ||
1182 | } | ||
1183 | 1291 | ||
1184 | /* If bytes left to transfer or linked tx resume job */ | 1292 | /* If bytes left to transfer or linked tx resume job */ |
1185 | if (d40_residue(d40c) || d40_tx_is_linked(d40c)) { | 1293 | if (d40_residue(d40c) || d40_tx_is_linked(d40c)) |
1186 | |||
1187 | if (chan_is_logical(d40c)) | ||
1188 | d40_config_set_event(d40c, true); | ||
1189 | |||
1190 | res = d40_channel_execute_command(d40c, D40_DMA_RUN); | 1294 | res = d40_channel_execute_command(d40c, D40_DMA_RUN); |
1191 | } | ||
1192 | 1295 | ||
1193 | no_suspend: | ||
1194 | pm_runtime_mark_last_busy(d40c->base->dev); | 1296 | pm_runtime_mark_last_busy(d40c->base->dev); |
1195 | pm_runtime_put_autosuspend(d40c->base->dev); | 1297 | pm_runtime_put_autosuspend(d40c->base->dev); |
1196 | spin_unlock_irqrestore(&d40c->lock, flags); | 1298 | spin_unlock_irqrestore(&d40c->lock, flags); |
1197 | return res; | 1299 | return res; |
1198 | } | 1300 | } |
1199 | 1301 | ||
1200 | static int d40_terminate_all(struct d40_chan *chan) | ||
1201 | { | ||
1202 | unsigned long flags; | ||
1203 | int ret = 0; | ||
1204 | |||
1205 | ret = d40_pause(chan); | ||
1206 | if (!ret && chan_is_physical(chan)) | ||
1207 | ret = d40_channel_execute_command(chan, D40_DMA_STOP); | ||
1208 | |||
1209 | spin_lock_irqsave(&chan->lock, flags); | ||
1210 | d40_term_all(chan); | ||
1211 | spin_unlock_irqrestore(&chan->lock, flags); | ||
1212 | |||
1213 | return ret; | ||
1214 | } | ||
1215 | |||
1216 | static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) | 1302 | static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) |
1217 | { | 1303 | { |
1218 | struct d40_chan *d40c = container_of(tx->chan, | 1304 | struct d40_chan *d40c = container_of(tx->chan, |
@@ -1232,20 +1318,6 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) | |||
1232 | 1318 | ||
1233 | static int d40_start(struct d40_chan *d40c) | 1319 | static int d40_start(struct d40_chan *d40c) |
1234 | { | 1320 | { |
1235 | if (d40c->base->rev == 0) { | ||
1236 | int err; | ||
1237 | |||
1238 | if (chan_is_logical(d40c)) { | ||
1239 | err = d40_channel_execute_command(d40c, | ||
1240 | D40_DMA_SUSPEND_REQ); | ||
1241 | if (err) | ||
1242 | return err; | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | if (chan_is_logical(d40c)) | ||
1247 | d40_config_set_event(d40c, true); | ||
1248 | |||
1249 | return d40_channel_execute_command(d40c, D40_DMA_RUN); | 1321 | return d40_channel_execute_command(d40c, D40_DMA_RUN); |
1250 | } | 1322 | } |
1251 | 1323 | ||
@@ -1258,10 +1330,10 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c) | |||
1258 | d40d = d40_first_queued(d40c); | 1330 | d40d = d40_first_queued(d40c); |
1259 | 1331 | ||
1260 | if (d40d != NULL) { | 1332 | if (d40d != NULL) { |
1261 | if (!d40c->busy) | 1333 | if (!d40c->busy) { |
1262 | d40c->busy = true; | 1334 | d40c->busy = true; |
1263 | 1335 | pm_runtime_get_sync(d40c->base->dev); | |
1264 | pm_runtime_get_sync(d40c->base->dev); | 1336 | } |
1265 | 1337 | ||
1266 | /* Remove from queue */ | 1338 | /* Remove from queue */ |
1267 | d40_desc_remove(d40d); | 1339 | d40_desc_remove(d40d); |
@@ -1388,8 +1460,8 @@ static void dma_tasklet(unsigned long data) | |||
1388 | 1460 | ||
1389 | return; | 1461 | return; |
1390 | 1462 | ||
1391 | err: | 1463 | err: |
1392 | /* Rescue manoeuvre if receiving double interrupts */ | 1464 | /* Rescue manouver if receiving double interrupts */ |
1393 | if (d40c->pending_tx > 0) | 1465 | if (d40c->pending_tx > 0) |
1394 | d40c->pending_tx--; | 1466 | d40c->pending_tx--; |
1395 | spin_unlock_irqrestore(&d40c->lock, flags); | 1467 | spin_unlock_irqrestore(&d40c->lock, flags); |
@@ -1770,7 +1842,6 @@ static int d40_config_memcpy(struct d40_chan *d40c) | |||
1770 | return 0; | 1842 | return 0; |
1771 | } | 1843 | } |
1772 | 1844 | ||
1773 | |||
1774 | static int d40_free_dma(struct d40_chan *d40c) | 1845 | static int d40_free_dma(struct d40_chan *d40c) |
1775 | { | 1846 | { |
1776 | 1847 | ||
@@ -1806,43 +1877,18 @@ static int d40_free_dma(struct d40_chan *d40c) | |||
1806 | } | 1877 | } |
1807 | 1878 | ||
1808 | pm_runtime_get_sync(d40c->base->dev); | 1879 | pm_runtime_get_sync(d40c->base->dev); |
1809 | res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); | 1880 | res = d40_channel_execute_command(d40c, D40_DMA_STOP); |
1810 | if (res) { | 1881 | if (res) { |
1811 | chan_err(d40c, "suspend failed\n"); | 1882 | chan_err(d40c, "stop failed\n"); |
1812 | goto out; | 1883 | goto out; |
1813 | } | 1884 | } |
1814 | 1885 | ||
1815 | if (chan_is_logical(d40c)) { | 1886 | d40_alloc_mask_free(phy, is_src, chan_is_logical(d40c) ? event : 0); |
1816 | /* Release logical channel, deactivate the event line */ | ||
1817 | 1887 | ||
1818 | d40_config_set_event(d40c, false); | 1888 | if (chan_is_logical(d40c)) |
1819 | d40c->base->lookup_log_chans[d40c->log_num] = NULL; | 1889 | d40c->base->lookup_log_chans[d40c->log_num] = NULL; |
1820 | 1890 | else | |
1821 | /* | 1891 | d40c->base->lookup_phy_chans[phy->num] = NULL; |
1822 | * Check if there are more logical allocation | ||
1823 | * on this phy channel. | ||
1824 | */ | ||
1825 | if (!d40_alloc_mask_free(phy, is_src, event)) { | ||
1826 | /* Resume the other logical channels if any */ | ||
1827 | if (d40_chan_has_events(d40c)) { | ||
1828 | res = d40_channel_execute_command(d40c, | ||
1829 | D40_DMA_RUN); | ||
1830 | if (res) | ||
1831 | chan_err(d40c, | ||
1832 | "Executing RUN command\n"); | ||
1833 | } | ||
1834 | goto out; | ||
1835 | } | ||
1836 | } else { | ||
1837 | (void) d40_alloc_mask_free(phy, is_src, 0); | ||
1838 | } | ||
1839 | |||
1840 | /* Release physical channel */ | ||
1841 | res = d40_channel_execute_command(d40c, D40_DMA_STOP); | ||
1842 | if (res) { | ||
1843 | chan_err(d40c, "Failed to stop channel\n"); | ||
1844 | goto out; | ||
1845 | } | ||
1846 | 1892 | ||
1847 | if (d40c->busy) { | 1893 | if (d40c->busy) { |
1848 | pm_runtime_mark_last_busy(d40c->base->dev); | 1894 | pm_runtime_mark_last_busy(d40c->base->dev); |
@@ -1852,7 +1898,6 @@ static int d40_free_dma(struct d40_chan *d40c) | |||
1852 | d40c->busy = false; | 1898 | d40c->busy = false; |
1853 | d40c->phy_chan = NULL; | 1899 | d40c->phy_chan = NULL; |
1854 | d40c->configured = false; | 1900 | d40c->configured = false; |
1855 | d40c->base->lookup_phy_chans[phy->num] = NULL; | ||
1856 | out: | 1901 | out: |
1857 | 1902 | ||
1858 | pm_runtime_mark_last_busy(d40c->base->dev); | 1903 | pm_runtime_mark_last_busy(d40c->base->dev); |
@@ -2371,6 +2416,31 @@ static void d40_issue_pending(struct dma_chan *chan) | |||
2371 | spin_unlock_irqrestore(&d40c->lock, flags); | 2416 | spin_unlock_irqrestore(&d40c->lock, flags); |
2372 | } | 2417 | } |
2373 | 2418 | ||
2419 | static void d40_terminate_all(struct dma_chan *chan) | ||
2420 | { | ||
2421 | unsigned long flags; | ||
2422 | struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); | ||
2423 | int ret; | ||
2424 | |||
2425 | spin_lock_irqsave(&d40c->lock, flags); | ||
2426 | |||
2427 | pm_runtime_get_sync(d40c->base->dev); | ||
2428 | ret = d40_channel_execute_command(d40c, D40_DMA_STOP); | ||
2429 | if (ret) | ||
2430 | chan_err(d40c, "Failed to stop channel\n"); | ||
2431 | |||
2432 | d40_term_all(d40c); | ||
2433 | pm_runtime_mark_last_busy(d40c->base->dev); | ||
2434 | pm_runtime_put_autosuspend(d40c->base->dev); | ||
2435 | if (d40c->busy) { | ||
2436 | pm_runtime_mark_last_busy(d40c->base->dev); | ||
2437 | pm_runtime_put_autosuspend(d40c->base->dev); | ||
2438 | } | ||
2439 | d40c->busy = false; | ||
2440 | |||
2441 | spin_unlock_irqrestore(&d40c->lock, flags); | ||
2442 | } | ||
2443 | |||
2374 | static int | 2444 | static int |
2375 | dma40_config_to_halfchannel(struct d40_chan *d40c, | 2445 | dma40_config_to_halfchannel(struct d40_chan *d40c, |
2376 | struct stedma40_half_channel_info *info, | 2446 | struct stedma40_half_channel_info *info, |
@@ -2551,7 +2621,8 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | |||
2551 | 2621 | ||
2552 | switch (cmd) { | 2622 | switch (cmd) { |
2553 | case DMA_TERMINATE_ALL: | 2623 | case DMA_TERMINATE_ALL: |
2554 | return d40_terminate_all(d40c); | 2624 | d40_terminate_all(chan); |
2625 | return 0; | ||
2555 | case DMA_PAUSE: | 2626 | case DMA_PAUSE: |
2556 | return d40_pause(d40c); | 2627 | return d40_pause(d40c); |
2557 | case DMA_RESUME: | 2628 | case DMA_RESUME: |
@@ -2908,6 +2979,12 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) | |||
2908 | dev_info(&pdev->dev, "hardware revision: %d @ 0x%x\n", | 2979 | dev_info(&pdev->dev, "hardware revision: %d @ 0x%x\n", |
2909 | rev, res->start); | 2980 | rev, res->start); |
2910 | 2981 | ||
2982 | if (rev < 2) { | ||
2983 | d40_err(&pdev->dev, "hardware revision: %d is not supported", | ||
2984 | rev); | ||
2985 | goto failure; | ||
2986 | } | ||
2987 | |||
2911 | plat_data = pdev->dev.platform_data; | 2988 | plat_data = pdev->dev.platform_data; |
2912 | 2989 | ||
2913 | /* Count the number of logical channels in use */ | 2990 | /* Count the number of logical channels in use */ |
@@ -2998,6 +3075,7 @@ failure: | |||
2998 | 3075 | ||
2999 | if (base) { | 3076 | if (base) { |
3000 | kfree(base->lcla_pool.alloc_map); | 3077 | kfree(base->lcla_pool.alloc_map); |
3078 | kfree(base->reg_val_backup_chan); | ||
3001 | kfree(base->lookup_log_chans); | 3079 | kfree(base->lookup_log_chans); |
3002 | kfree(base->lookup_phy_chans); | 3080 | kfree(base->lookup_phy_chans); |
3003 | kfree(base->phy_res); | 3081 | kfree(base->phy_res); |
diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 8d3d490968a3..51e8e5396e9b 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h | |||
@@ -62,8 +62,6 @@ | |||
62 | #define D40_SREG_ELEM_LOG_LIDX_MASK (0xFF << D40_SREG_ELEM_LOG_LIDX_POS) | 62 | #define D40_SREG_ELEM_LOG_LIDX_MASK (0xFF << D40_SREG_ELEM_LOG_LIDX_POS) |
63 | 63 | ||
64 | /* Link register */ | 64 | /* Link register */ |
65 | #define D40_DEACTIVATE_EVENTLINE 0x0 | ||
66 | #define D40_ACTIVATE_EVENTLINE 0x1 | ||
67 | #define D40_EVENTLINE_POS(i) (2 * i) | 65 | #define D40_EVENTLINE_POS(i) (2 * i) |
68 | #define D40_EVENTLINE_MASK(i) (0x3 << D40_EVENTLINE_POS(i)) | 66 | #define D40_EVENTLINE_MASK(i) (0x3 << D40_EVENTLINE_POS(i)) |
69 | 67 | ||