1/*
2* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without modification, are permitted
5* provided that the following conditions are met:
6*    * Redistributions of source code must retain the above copyright notice, this list of
7*      conditions and the following disclaimer.
8*    * Redistributions in binary form must reproduce the above copyright notice, this list of
9*      conditions and the following disclaimer in the documentation and/or other materials provided
10*      with the distribution.
11*    * Neither the name of The Linux Foundation nor the names of its contributors may be used to
12*      endorse or promote products derived from this software without specific prior written
13*      permission.
14*
15* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17* NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*/
24
25#include <utils/constants.h>
26#include <utils/debug.h>
27#include <core/buffer_allocator.h>
28
29#include "comp_manager.h"
30#include "strategy.h"
31
32#define __CLASS__ "CompManager"
33
34namespace sdm {
35
36static bool NeedsScaledComposition(const DisplayConfigVariableInfo &fb_config,
37                                   const HWMixerAttributes &mixer_attributes) {
38  return ((fb_config.x_pixels != mixer_attributes.width) ||
39          (fb_config.y_pixels != mixer_attributes.height));
40}
41
42DisplayError CompManager::Init(const HWResourceInfo &hw_res_info,
43                               ExtensionInterface *extension_intf,
44                               BufferAllocator *buffer_allocator,
45                               BufferSyncHandler *buffer_sync_handler,
46                               SocketHandler *socket_handler) {
47  SCOPE_LOCK(locker_);
48
49  DisplayError error = kErrorNone;
50
51  if (extension_intf) {
52    error = extension_intf->CreateResourceExtn(hw_res_info, buffer_allocator, buffer_sync_handler,
53                                               &resource_intf_);
54    extension_intf->CreateDppsControlExtn(&dpps_ctrl_intf_, socket_handler);
55  } else {
56    error = ResourceDefault::CreateResourceDefault(hw_res_info, &resource_intf_);
57  }
58
59  if (error != kErrorNone) {
60    if (extension_intf) {
61      extension_intf->DestroyDppsControlExtn(dpps_ctrl_intf_);
62    }
63    return error;
64  }
65
66  hw_res_info_ = hw_res_info;
67  buffer_allocator_ = buffer_allocator;
68  extension_intf_ = extension_intf;
69
70  return error;
71}
72
73DisplayError CompManager::Deinit() {
74  SCOPE_LOCK(locker_);
75
76  if (extension_intf_) {
77    extension_intf_->DestroyResourceExtn(resource_intf_);
78    extension_intf_->DestroyDppsControlExtn(dpps_ctrl_intf_);
79  } else {
80    ResourceDefault::DestroyResourceDefault(resource_intf_);
81  }
82
83  return kErrorNone;
84}
85
86DisplayError CompManager::RegisterDisplay(DisplayType type,
87                                          const HWDisplayAttributes &display_attributes,
88                                          const HWPanelInfo &hw_panel_info,
89                                          const HWMixerAttributes &mixer_attributes,
90                                          const DisplayConfigVariableInfo &fb_config,
91                                          Handle *display_ctx) {
92  SCOPE_LOCK(locker_);
93
94  DisplayError error = kErrorNone;
95
96  DisplayCompositionContext *display_comp_ctx = new DisplayCompositionContext();
97  if (!display_comp_ctx) {
98    return kErrorMemory;
99  }
100
101  Strategy *&strategy = display_comp_ctx->strategy;
102  strategy = new Strategy(extension_intf_, buffer_allocator_, type, hw_res_info_, hw_panel_info,
103                          mixer_attributes, display_attributes, fb_config);
104  if (!strategy) {
105    DLOGE("Unable to create strategy");
106    delete display_comp_ctx;
107    return kErrorMemory;
108  }
109
110  error = strategy->Init();
111  if (error != kErrorNone) {
112    delete strategy;
113    delete display_comp_ctx;
114    return error;
115  }
116
117  error = resource_intf_->RegisterDisplay(type, display_attributes, hw_panel_info, mixer_attributes,
118                                          &display_comp_ctx->display_resource_ctx);
119  if (error != kErrorNone) {
120    strategy->Deinit();
121    delete strategy;
122    delete display_comp_ctx;
123    display_comp_ctx = NULL;
124    return error;
125  }
126
127  registered_displays_[type] = 1;
128  display_comp_ctx->is_primary_panel = hw_panel_info.is_primary_panel;
129  display_comp_ctx->display_type = type;
130  display_comp_ctx->fb_config = fb_config;
131  *display_ctx = display_comp_ctx;
132  // New non-primary display device has been added, so move the composition mode to safe mode until
133  // resources for the added display is configured properly.
134  if (!display_comp_ctx->is_primary_panel) {
135    safe_mode_ = true;
136    max_sde_ext_layers_ = UINT32(Debug::GetExtMaxlayers());
137  }
138
139  display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes);
140  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
141           "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(),
142           display_comp_ctx->display_type);
143
144  return kErrorNone;
145}
146
147DisplayError CompManager::UnregisterDisplay(Handle display_ctx) {
148  SCOPE_LOCK(locker_);
149
150  DisplayCompositionContext *display_comp_ctx =
151                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
152
153  if (!display_comp_ctx) {
154    return kErrorParameters;
155  }
156
157  resource_intf_->UnregisterDisplay(display_comp_ctx->display_resource_ctx);
158
159  Strategy *&strategy = display_comp_ctx->strategy;
160  strategy->Deinit();
161  delete strategy;
162
163  registered_displays_[display_comp_ctx->display_type] = 0;
164  configured_displays_[display_comp_ctx->display_type] = 0;
165
166  if (display_comp_ctx->display_type == kHDMI) {
167    max_layers_ = kMaxSDELayers;
168  }
169
170  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
171           "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(),
172           display_comp_ctx->display_type);
173
174  delete display_comp_ctx;
175  display_comp_ctx = NULL;
176  return kErrorNone;
177}
178
179DisplayError CompManager::ReconfigureDisplay(Handle comp_handle,
180                                             const HWDisplayAttributes &display_attributes,
181                                             const HWPanelInfo &hw_panel_info,
182                                             const HWMixerAttributes &mixer_attributes,
183                                             const DisplayConfigVariableInfo &fb_config) {
184  SCOPE_LOCK(locker_);
185
186  DisplayError error = kErrorNone;
187  DisplayCompositionContext *display_comp_ctx =
188                             reinterpret_cast<DisplayCompositionContext *>(comp_handle);
189
190  error = resource_intf_->ReconfigureDisplay(display_comp_ctx->display_resource_ctx,
191                                             display_attributes, hw_panel_info, mixer_attributes);
192  if (error != kErrorNone) {
193    return error;
194  }
195
196  if (display_comp_ctx->strategy) {
197    error = display_comp_ctx->strategy->Reconfigure(hw_panel_info, display_attributes,
198                                                    mixer_attributes, fb_config);
199    if (error != kErrorNone) {
200      DLOGE("Unable to Reconfigure strategy.");
201      display_comp_ctx->strategy->Deinit();
202      delete display_comp_ctx->strategy;
203      display_comp_ctx->strategy = NULL;
204      return error;
205    }
206  }
207
208  // For HDMI S3D mode, set max_layers_ to 0 so that primary display would fall back
209  // to GPU composition to release pipes for HDMI.
210  if (display_comp_ctx->display_type == kHDMI) {
211    if (hw_panel_info.s3d_mode != kS3DModeNone) {
212      max_layers_ = 0;
213    } else {
214      max_layers_ = kMaxSDELayers;
215    }
216  }
217
218  display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes);
219  // Update new resolution.
220  display_comp_ctx->fb_config = fb_config;
221
222  return error;
223}
224
225void CompManager::PrepareStrategyConstraints(Handle comp_handle, HWLayers *hw_layers) {
226  DisplayCompositionContext *display_comp_ctx =
227                             reinterpret_cast<DisplayCompositionContext *>(comp_handle);
228  StrategyConstraints *constraints = &display_comp_ctx->constraints;
229  bool low_end_hw = ((hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe +
230                    hw_res_info_.num_dma_pipe) <= kSafeModeThreshold);
231
232  constraints->safe_mode = safe_mode_;
233  constraints->use_cursor = false;
234  constraints->max_layers = max_layers_;
235
236  // Limit 2 layer SDE Comp if its not a Primary Display.
237  // Safe mode is the policy for External display on a low end device.
238  if (!display_comp_ctx->is_primary_panel) {
239    constraints->max_layers = max_sde_ext_layers_;
240    constraints->safe_mode = (low_end_hw && !hw_res_info_.separate_rotator) ? true : safe_mode_;
241    if(hw_layers->info.stack->flags.secure_present)
242        secure_external_layer_ = true;
243    else
244        secure_external_layer_ = false;
245  }
246
247  // When Secure layer is present on external, GPU composition should be policy
248  // for Primary on low end devices
249  if(display_comp_ctx->is_primary_panel && (registered_displays_.count() > 1)
250          && low_end_hw && secure_external_layer_) {
251    DLOGV_IF(kTagCompManager,"Secure layer present for LET. Fallingback to GPU");
252    hw_layers->info.stack->flags.skip_present = 1;
253    for(auto &layer : hw_layers->info.stack->layers) {
254      if(layer->composition != kCompositionGPUTarget) {
255        layer->flags.skip = 1;
256      }
257    }
258  }
259
260  // If a strategy fails after successfully allocating resources, then set safe mode
261  if (display_comp_ctx->remaining_strategies != display_comp_ctx->max_strategies) {
262    constraints->safe_mode = true;
263  }
264
265  // Set use_cursor constraint to Strategy
266  constraints->use_cursor = display_comp_ctx->valid_cursor;
267
268  // TODO(user): App layer count will change for hybrid composition
269  uint32_t app_layer_count = UINT32(hw_layers->info.stack->layers.size()) - 1;
270  if (display_comp_ctx->idle_fallback || display_comp_ctx->thermal_fallback_) {
271    // Handle the idle timeout by falling back
272    constraints->safe_mode = true;
273  }
274
275  // Avoid safe mode, if there is only one app layer.
276  if (app_layer_count == 1) {
277     constraints->safe_mode = false;
278  }
279}
280
281void CompManager::PrePrepare(Handle display_ctx, HWLayers *hw_layers) {
282  SCOPE_LOCK(locker_);
283  DisplayCompositionContext *display_comp_ctx =
284                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
285  display_comp_ctx->valid_cursor = SupportLayerAsCursor(display_comp_ctx, hw_layers);
286
287  // pu constraints
288  display_comp_ctx->pu_constraints.enable_cursor_pu = display_comp_ctx->valid_cursor;
289
290  display_comp_ctx->strategy->Start(&hw_layers->info, &display_comp_ctx->max_strategies,
291                                    display_comp_ctx->pu_constraints);
292  display_comp_ctx->remaining_strategies = display_comp_ctx->max_strategies;
293}
294
295DisplayError CompManager::Prepare(Handle display_ctx, HWLayers *hw_layers) {
296  SCOPE_LOCK(locker_);
297
298  DisplayCompositionContext *display_comp_ctx =
299                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
300  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
301
302  DisplayError error = kErrorUndefined;
303
304  PrepareStrategyConstraints(display_ctx, hw_layers);
305
306  // Select a composition strategy, and try to allocate resources for it.
307  resource_intf_->Start(display_resource_ctx);
308
309  bool exit = false;
310  uint32_t &count = display_comp_ctx->remaining_strategies;
311  for (; !exit && count > 0; count--) {
312    error = display_comp_ctx->strategy->GetNextStrategy(&display_comp_ctx->constraints);
313    if (error != kErrorNone) {
314      // Composition strategies exhausted. Resource Manager could not allocate resources even for
315      // GPU composition. This will never happen.
316      exit = true;
317    }
318
319    if (!exit) {
320      error = resource_intf_->Prepare(display_resource_ctx, hw_layers);
321      // Exit if successfully prepared resource, else try next strategy.
322      exit = (error == kErrorNone);
323    }
324  }
325
326  if (error != kErrorNone) {
327    resource_intf_->Stop(display_resource_ctx, hw_layers);
328    DLOGE("Composition strategies exhausted for display = %d", display_comp_ctx->display_type);
329    return error;
330  }
331
332  error = resource_intf_->Stop(display_resource_ctx, hw_layers);
333
334  return error;
335}
336
337DisplayError CompManager::PostPrepare(Handle display_ctx, HWLayers *hw_layers) {
338  SCOPE_LOCK(locker_);
339  DisplayCompositionContext *display_comp_ctx =
340                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
341  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
342
343  DisplayError error = kErrorNone;
344  error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers);
345  if (error != kErrorNone) {
346    return error;
347  }
348
349  display_comp_ctx->strategy->Stop();
350
351  return kErrorNone;
352}
353
354DisplayError CompManager::Commit(Handle display_ctx, HWLayers *hw_layers) {
355  SCOPE_LOCK(locker_);
356
357  DisplayCompositionContext *display_comp_ctx =
358                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
359
360  return resource_intf_->Commit(display_comp_ctx->display_resource_ctx, hw_layers);
361}
362
363DisplayError CompManager::ReConfigure(Handle display_ctx, HWLayers *hw_layers) {
364  SCOPE_LOCK(locker_);
365
366  DisplayCompositionContext *display_comp_ctx =
367                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
368  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
369
370  DisplayError error = kErrorUndefined;
371  resource_intf_->Start(display_resource_ctx);
372  error = resource_intf_->Prepare(display_resource_ctx, hw_layers);
373
374  if (error != kErrorNone) {
375    DLOGE("Reconfigure failed for display = %d", display_comp_ctx->display_type);
376  }
377
378  resource_intf_->Stop(display_resource_ctx, hw_layers);
379  if (error != kErrorNone) {
380      error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers);
381  }
382
383  return error;
384}
385
386DisplayError CompManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
387  SCOPE_LOCK(locker_);
388
389  DisplayError error = kErrorNone;
390  DisplayCompositionContext *display_comp_ctx =
391                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
392  configured_displays_[display_comp_ctx->display_type] = 1;
393  if (configured_displays_ == registered_displays_) {
394    safe_mode_ = false;
395  }
396
397  error = resource_intf_->PostCommit(display_comp_ctx->display_resource_ctx, hw_layers);
398  if (error != kErrorNone) {
399    return error;
400  }
401
402  display_comp_ctx->idle_fallback = false;
403
404  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
405           "display type %d", registered_displays_, configured_displays_,
406           display_comp_ctx->display_type);
407
408  return kErrorNone;
409}
410
411void CompManager::Purge(Handle display_ctx) {
412  SCOPE_LOCK(locker_);
413
414  DisplayCompositionContext *display_comp_ctx =
415                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
416
417  resource_intf_->Purge(display_comp_ctx->display_resource_ctx);
418
419  display_comp_ctx->strategy->Purge();
420}
421
422DisplayError CompManager::SetIdleTimeoutMs(Handle display_ctx, uint32_t active_ms) {
423  SCOPE_LOCK(locker_);
424
425  DisplayCompositionContext *display_comp_ctx =
426                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
427
428  return display_comp_ctx->strategy->SetIdleTimeoutMs(active_ms);
429}
430
431void CompManager::ProcessIdleTimeout(Handle display_ctx) {
432  SCOPE_LOCK(locker_);
433
434  DisplayCompositionContext *display_comp_ctx =
435                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
436
437  if (!display_comp_ctx) {
438    return;
439  }
440
441  display_comp_ctx->idle_fallback = true;
442}
443
444void CompManager::ProcessThermalEvent(Handle display_ctx, int64_t thermal_level) {
445  SCOPE_LOCK(locker_);
446
447  DisplayCompositionContext *display_comp_ctx =
448          reinterpret_cast<DisplayCompositionContext *>(display_ctx);
449
450  if (thermal_level >= kMaxThermalLevel) {
451    display_comp_ctx->thermal_fallback_ = true;
452  } else {
453    display_comp_ctx->thermal_fallback_ = false;
454  }
455}
456
457void CompManager::ProcessIdlePowerCollapse(Handle display_ctx) {
458  SCOPE_LOCK(locker_);
459
460  DisplayCompositionContext *display_comp_ctx =
461          reinterpret_cast<DisplayCompositionContext *>(display_ctx);
462
463  if (display_comp_ctx) {
464    resource_intf_->Perform(ResourceInterface::kCmdResetScalarLUT,
465                            display_comp_ctx->display_resource_ctx);
466  }
467}
468
469DisplayError CompManager::SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) {
470  SCOPE_LOCK(locker_);
471
472  DisplayError error = kErrorNone;
473  DisplayCompositionContext *display_comp_ctx =
474                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
475
476  if (display_comp_ctx) {
477    error = resource_intf_->SetMaxMixerStages(display_comp_ctx->display_resource_ctx,
478                                              max_mixer_stages);
479  }
480
481  return error;
482}
483
484void CompManager::ControlPartialUpdate(Handle display_ctx, bool enable) {
485  SCOPE_LOCK(locker_);
486
487  DisplayCompositionContext *display_comp_ctx =
488                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
489  display_comp_ctx->pu_constraints.enable = enable;
490}
491
492DisplayError CompManager::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
493                                          bool rotate90) {
494  BufferLayout layout = Debug::IsUbwcTiledFrameBuffer() ? kUBWC : kLinear;
495  return resource_intf_->ValidateScaling(crop, dst, rotate90, layout, true);
496}
497
498DisplayError CompManager::ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers,
499                                                 int x, int y) {
500  DisplayCompositionContext *display_comp_ctx =
501                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
502  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
503  return resource_intf_->ValidateAndSetCursorPosition(display_resource_ctx, hw_layers, x, y,
504                                                      &display_comp_ctx->fb_config);
505}
506
507bool CompManager::SupportLayerAsCursor(Handle comp_handle, HWLayers *hw_layers) {
508  DisplayCompositionContext *display_comp_ctx =
509                             reinterpret_cast<DisplayCompositionContext *>(comp_handle);
510  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
511  LayerStack *layer_stack = hw_layers->info.stack;
512  bool supported = false;
513  int32_t gpu_index = -1;
514
515  // HW Cursor cannot be used, if Display configuration needs scaled composition.
516  if (display_comp_ctx->scaled_composition || !layer_stack->flags.cursor_present) {
517    return supported;
518  }
519
520  for (int32_t i = INT32(layer_stack->layers.size() - 1); i >= 0; i--) {
521    Layer *layer = layer_stack->layers.at(UINT32(i));
522    if (layer->composition == kCompositionGPUTarget) {
523      gpu_index = i;
524      break;
525    }
526  }
527  if (gpu_index <= 0) {
528    return supported;
529  }
530  Layer *cursor_layer = layer_stack->layers.at(UINT32(gpu_index) - 1);
531  if (cursor_layer->flags.cursor && !cursor_layer->flags.skip &&
532      resource_intf_->ValidateCursorConfig(display_resource_ctx,
533                                           cursor_layer, true) == kErrorNone) {
534    supported = true;
535  }
536
537  return supported;
538}
539
540DisplayError CompManager::SetMaxBandwidthMode(HWBwModes mode) {
541  if ((hw_res_info_.has_dyn_bw_support == false) || (mode >= kBwModeMax)) {
542    return kErrorNotSupported;
543  }
544
545  return resource_intf_->SetMaxBandwidthMode(mode);
546}
547
548DisplayError CompManager::GetScaleLutConfig(HWScaleLutInfo *lut_info) {
549  return resource_intf_->GetScaleLutConfig(lut_info);
550}
551
552DisplayError CompManager::SetDetailEnhancerData(Handle display_ctx,
553                                                const DisplayDetailEnhancerData &de_data) {
554  SCOPE_LOCK(locker_);
555
556  DisplayCompositionContext *display_comp_ctx =
557                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
558
559  return resource_intf_->SetDetailEnhancerData(display_comp_ctx->display_resource_ctx, de_data);
560}
561
562DisplayError CompManager::SetCompositionState(Handle display_ctx,
563                                              LayerComposition composition_type, bool enable) {
564  SCOPE_LOCK(locker_);
565
566  DisplayCompositionContext *display_comp_ctx =
567                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
568
569  return display_comp_ctx->strategy->SetCompositionState(composition_type, enable);
570}
571
572DisplayError CompManager::ControlDpps(bool enable) {
573  if (dpps_ctrl_intf_) {
574    return enable ? dpps_ctrl_intf_->On() : dpps_ctrl_intf_->Off();
575  }
576
577  return kErrorNone;
578}
579
580bool CompManager::SetDisplayState(Handle display_ctx,
581                                  DisplayState state, DisplayType display_type) {
582  display_state_[display_type] = state;
583
584  switch (state) {
585  case kStateOff:
586    Purge(display_ctx);
587    configured_displays_.reset(display_type);
588    DLOGV_IF(kTagCompManager, "configured_displays_ = 0x%x", configured_displays_);
589    break;
590
591  case kStateOn:
592    if (registered_displays_.count() > 1) {
593      safe_mode_ = true;
594      DLOGV_IF(kTagCompManager, "safe_mode = %d", safe_mode_);
595    }
596    break;
597
598  default:
599    break;
600  }
601
602  return true;
603}
604
605}  // namespace sdm
606