Browse Source

Make requests from configured power

Now the DPM tests if the configuration holds a current or a power, and
if it's a power, it calculates current at the necessary voltage(s) based
on that power.  This is used when making requests, when advertising our
Sink_Capabilities, and when checking Type-C Current advertisements.
Clara Hobbs 6 years ago
parent
commit
974bd90424
2 changed files with 47 additions and 20 deletions
  1. 3
    3
      lib/include/pd.h
  2. 44
    17
      src/device_policy_manager.c

+ 3
- 3
lib/include/pd.h View File

328
 #define PD_PDV2MV(pdv) ((pdv) * 50)
328
 #define PD_PDV2MV(pdv) ((pdv) * 50)
329
 #define PD_PAV2MV(pav) ((pav) * 100)
329
 #define PD_PAV2MV(pav) ((pav) * 100)
330
 
330
 
331
-#define PD_MA2PDI(ma) ((ma) / 10)
332
-#define PD_MA2PAI(ma) ((ma) / 50)
333
-#define PD_CA2PAI(ca) ((ca) / 5)
331
+#define PD_MA2PDI(ma) (((ma) + 10 - 1) / 10)
332
+#define PD_MA2PAI(ma) (((ma) + 50 - 1) / 50)
333
+#define PD_CA2PAI(ca) (((ca) + 5 - 1) / 5)
334
 #define PD_PDI2MA(pdi) ((pdi) * 10)
334
 #define PD_PDI2MA(pdi) ((pdi) * 10)
335
 #define PD_PAI2MA(pai) ((pai) * 50)
335
 #define PD_PAI2MA(pai) ((pai) * 50)
336
 #define PD_PAI2CA(pai) ((pai) * 5)
336
 #define PD_PAI2CA(pai) ((pai) * 5)

+ 44
- 17
src/device_policy_manager.c View File

32
 #define DPM_MIN_CURRENT PD_MA2PDI(100)
32
 #define DPM_MIN_CURRENT PD_MA2PDI(100)
33
 
33
 
34
 
34
 
35
+/*
36
+ * Return the current specified by the given PDBS configuration object at the
37
+ * given voltage (in millivolts), in centiamperes.
38
+ */
39
+static uint16_t dpm_get_current(struct pdbs_config *scfg, uint16_t mv)
40
+{
41
+    switch (scfg->flags & PDBS_CONFIG_FLAGS_CURRENT_DEFN) {
42
+        case PDBS_CONFIG_FLAGS_CURRENT_DEFN_I:
43
+            return scfg->i;
44
+        case PDBS_CONFIG_FLAGS_CURRENT_DEFN_P:
45
+            return (scfg->p * 1000 + mv - 1) / mv;
46
+    }
47
+}
48
+
49
+
35
 /*
50
 /*
36
  * Find the index of the first PDO from capabilities in the voltage range,
51
  * Find the index of the first PDO from capabilities in the voltage range,
37
  * using the desired order.
52
  * using the desired order.
59
     while (0 <= i && i < numobj) {
74
     while (0 <= i && i < numobj) {
60
         /* If we have a fixed PDO, its V is within our range, and its I is at
75
         /* If we have a fixed PDO, its V is within our range, and its I is at
61
          * least our desired I */
76
          * least our desired I */
77
+        uint16_t v = PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]);
62
         if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED
78
         if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED
63
-                && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= scfg->i
64
-                && PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]) >= PD_MV2PDV(scfg->vmin)
65
-                && PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]) <= PD_MV2PDV(scfg->vmax)) {
79
+                && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= dpm_get_current(scfg, PD_PDV2MV(v))
80
+                && v >= PD_MV2PDV(scfg->vmin)
81
+                && v <= PD_MV2PDV(scfg->vmax)) {
66
             return i;
82
             return i;
67
         }
83
         }
68
         i += step;
84
         i += step;
100
     /* Get whether or not the power supply is constrained */
116
     /* Get whether or not the power supply is constrained */
101
     dpm_data->_unconstrained_power = caps->obj[0] & PD_PDO_SRC_FIXED_UNCONSTRAINED;
117
     dpm_data->_unconstrained_power = caps->obj[0] & PD_PDO_SRC_FIXED_UNCONSTRAINED;
102
 
118
 
119
+    /* Get the current we want */
120
+    uint16_t current = dpm_get_current(scfg, scfg->v);
121
+
103
     /* Make sure we have configuration */
122
     /* Make sure we have configuration */
104
     if (scfg != NULL && dpm_data->output_enabled) {
123
     if (scfg != NULL && dpm_data->output_enabled) {
105
         /* Look at the PDOs to see if one matches our desires */
124
         /* Look at the PDOs to see if one matches our desires */
108
              * at least our desired I */
127
              * at least our desired I */
109
             if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED
128
             if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED
110
                     && PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]) == PD_MV2PDV(scfg->v)
129
                     && PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]) == PD_MV2PDV(scfg->v)
111
-                    && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= scfg->i) {
130
+                    && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= current) {
112
                 /* We got what we wanted, so build a request for that */
131
                 /* We got what we wanted, so build a request for that */
113
                 request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
132
                 request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
114
                     | PD_NUMOBJ(1);
133
                     | PD_NUMOBJ(1);
115
                 if (scfg->flags & PDBS_CONFIG_FLAGS_GIVEBACK) {
134
                 if (scfg->flags & PDBS_CONFIG_FLAGS_GIVEBACK) {
116
                     /* GiveBack enabled */
135
                     /* GiveBack enabled */
117
                     request->obj[0] = PD_RDO_FV_MIN_CURRENT_SET(DPM_MIN_CURRENT)
136
                     request->obj[0] = PD_RDO_FV_MIN_CURRENT_SET(DPM_MIN_CURRENT)
118
-                        | PD_RDO_FV_CURRENT_SET(scfg->i)
137
+                        | PD_RDO_FV_CURRENT_SET(current)
119
                         | PD_RDO_NO_USB_SUSPEND | PD_RDO_GIVEBACK
138
                         | PD_RDO_NO_USB_SUSPEND | PD_RDO_GIVEBACK
120
                         | PD_RDO_OBJPOS_SET(i + 1);
139
                         | PD_RDO_OBJPOS_SET(i + 1);
121
                 } else {
140
                 } else {
122
                     /* GiveBack disabled */
141
                     /* GiveBack disabled */
123
-                    request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(scfg->i)
124
-                        | PD_RDO_FV_CURRENT_SET(scfg->i)
142
+                    request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(current)
143
+                        | PD_RDO_FV_CURRENT_SET(current)
125
                         | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
144
                         | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
126
                 }
145
                 }
127
                 if (dpm_data->usb_comms) {
146
                 if (dpm_data->usb_comms) {
140
                     && (caps->obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS
159
                     && (caps->obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS
141
                     && PD_APDO_PPS_MAX_VOLTAGE_GET(caps->obj[i]) >= PD_MV2PAV(scfg->v)
160
                     && PD_APDO_PPS_MAX_VOLTAGE_GET(caps->obj[i]) >= PD_MV2PAV(scfg->v)
142
                     && PD_APDO_PPS_MIN_VOLTAGE_GET(caps->obj[i]) <= PD_MV2PAV(scfg->v)
161
                     && PD_APDO_PPS_MIN_VOLTAGE_GET(caps->obj[i]) <= PD_MV2PAV(scfg->v)
143
-                    && PD_APDO_PPS_CURRENT_GET(caps->obj[i]) >= PD_CA2PAI(scfg->i)) {
162
+                    && PD_APDO_PPS_CURRENT_GET(caps->obj[i]) >= PD_CA2PAI(current)) {
144
                 /* We got what we wanted, so build a request for that */
163
                 /* We got what we wanted, so build a request for that */
145
                 request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
164
                 request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
146
                     | PD_NUMOBJ(1);
165
                     | PD_NUMOBJ(1);
147
 
166
 
148
                 /* Build a request */
167
                 /* Build a request */
149
-                request->obj[0] = PD_RDO_PROG_CURRENT_SET(PD_CA2PAI(scfg->i))
168
+                request->obj[0] = PD_RDO_PROG_CURRENT_SET(PD_CA2PAI(current))
150
                     | PD_RDO_PROG_VOLTAGE_SET(PD_MV2PRV(scfg->v))
169
                     | PD_RDO_PROG_VOLTAGE_SET(PD_MV2PRV(scfg->v))
151
                     | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
170
                     | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
152
                 if (dpm_data->usb_comms) {
171
                 if (dpm_data->usb_comms) {
166
             /* We got what we wanted, so build a request for that */
185
             /* We got what we wanted, so build a request for that */
167
             request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
186
             request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
168
                 | PD_NUMOBJ(1);
187
                 | PD_NUMOBJ(1);
188
+            /* Get the current we need at this voltage */
189
+            current = dpm_get_current(scfg, PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i])));
169
             if (scfg->flags & PDBS_CONFIG_FLAGS_GIVEBACK) {
190
             if (scfg->flags & PDBS_CONFIG_FLAGS_GIVEBACK) {
170
                 /* GiveBack enabled */
191
                 /* GiveBack enabled */
171
                 request->obj[0] = PD_RDO_FV_MIN_CURRENT_SET(DPM_MIN_CURRENT)
192
                 request->obj[0] = PD_RDO_FV_MIN_CURRENT_SET(DPM_MIN_CURRENT)
172
-                    | PD_RDO_FV_CURRENT_SET(scfg->i)
193
+                    | PD_RDO_FV_CURRENT_SET(current)
173
                     | PD_RDO_NO_USB_SUSPEND | PD_RDO_GIVEBACK
194
                     | PD_RDO_NO_USB_SUSPEND | PD_RDO_GIVEBACK
174
                     | PD_RDO_OBJPOS_SET(i + 1);
195
                     | PD_RDO_OBJPOS_SET(i + 1);
175
             } else {
196
             } else {
176
                 /* GiveBack disabled */
197
                 /* GiveBack disabled */
177
-                request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(scfg->i)
178
-                    | PD_RDO_FV_CURRENT_SET(scfg->i)
198
+                request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(current)
199
+                    | PD_RDO_FV_CURRENT_SET(current)
179
                     | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
200
                     | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
180
             }
201
             }
181
             if (dpm_data->usb_comms) {
202
             if (dpm_data->usb_comms) {
232
     }
253
     }
233
 
254
 
234
     if (scfg != NULL) {
255
     if (scfg != NULL) {
256
+        /* Get the current we want */
257
+        uint16_t current = dpm_get_current(scfg, scfg->v);
235
         /* Add a PDO for the desired power. */
258
         /* Add a PDO for the desired power. */
236
         cap->obj[numobj++] = PD_PDO_TYPE_FIXED
259
         cap->obj[numobj++] = PD_PDO_TYPE_FIXED
237
             | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(scfg->v))
260
             | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(scfg->v))
238
-            | PD_PDO_SNK_FIXED_CURRENT_SET(scfg->i);
261
+            | PD_PDO_SNK_FIXED_CURRENT_SET(current);
239
 
262
 
240
         /* Get the PDO from the voltage range */
263
         /* Get the PDO from the voltage range */
241
         int8_t i = dpm_get_range_fixed_pdo_index(dpm_data->capabilities, scfg);
264
         int8_t i = dpm_get_range_fixed_pdo_index(dpm_data->capabilities, scfg);
243
         /* If it's vSafe5V, set our vSafe5V's current to what we want */
266
         /* If it's vSafe5V, set our vSafe5V's current to what we want */
244
         if (i == 0) {
267
         if (i == 0) {
245
             cap->obj[0] &= ~PD_PDO_SNK_FIXED_CURRENT;
268
             cap->obj[0] &= ~PD_PDO_SNK_FIXED_CURRENT;
246
-            cap->obj[0] |= PD_PDO_SNK_FIXED_CURRENT_SET(scfg->i);
269
+            cap->obj[0] |= PD_PDO_SNK_FIXED_CURRENT_SET(current);
247
         } else {
270
         } else {
248
             /* If we want more than 5 V, set the Higher Capability flag */
271
             /* If we want more than 5 V, set the Higher Capability flag */
249
             if (PD_MV2PDV(scfg->v) != PD_MV2PDV(5000)) {
272
             if (PD_MV2PDV(scfg->v) != PD_MV2PDV(5000)) {
274
             cap->obj[numobj++] = PD_PDO_TYPE_AUGMENTED | PD_APDO_TYPE_PPS
297
             cap->obj[numobj++] = PD_PDO_TYPE_AUGMENTED | PD_APDO_TYPE_PPS
275
                 | PD_APDO_PPS_MAX_VOLTAGE_SET(PD_MV2PAV(scfg->v))
298
                 | PD_APDO_PPS_MAX_VOLTAGE_SET(PD_MV2PAV(scfg->v))
276
                 | PD_APDO_PPS_MIN_VOLTAGE_SET(PD_MV2PAV(scfg->v))
299
                 | PD_APDO_PPS_MIN_VOLTAGE_SET(PD_MV2PAV(scfg->v))
277
-                | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(scfg->i));
300
+                | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(current));
278
         }
301
         }
279
     }
302
     }
280
 
303
 
317
 
340
 
318
     /* If we have no configuration or don't want 5 V, Type-C Current can't
341
     /* If we have no configuration or don't want 5 V, Type-C Current can't
319
      * possibly satisfy our needs */
342
      * possibly satisfy our needs */
343
+    /* TODO Check if 5 V is inside the voltage range */
320
     if (scfg == NULL || PD_MV2PDV(scfg->v) != PD_MV2PDV(5000)) {
344
     if (scfg == NULL || PD_MV2PDV(scfg->v) != PD_MV2PDV(5000)) {
321
         dpm_data->_capability_match = false;
345
         dpm_data->_capability_match = false;
322
         return false;
346
         return false;
323
     }
347
     }
324
 
348
 
349
+    /* Get the current we want */
350
+    uint16_t current = dpm_get_current(scfg, scfg->v);
351
+
325
     /* If 1.5 A is available and we want no more than that, great. */
352
     /* If 1.5 A is available and we want no more than that, great. */
326
-    if (tcc == fusb_tcc_1_5 && scfg->i <= 150) {
353
+    if (tcc == fusb_tcc_1_5 && current <= 150) {
327
         dpm_data->_capability_match = true;
354
         dpm_data->_capability_match = true;
328
         return true;
355
         return true;
329
     }
356
     }
330
     /* If 3 A is available and we want no more than that, that's great too. */
357
     /* If 3 A is available and we want no more than that, that's great too. */
331
-    if (tcc == fusb_tcc_3_0 && scfg->i <= 300) {
358
+    if (tcc == fusb_tcc_3_0 && current <= 300) {
332
         dpm_data->_capability_match = true;
359
         dpm_data->_capability_match = true;
333
         return true;
360
         return true;
334
     }
361
     }

Loading…
Cancel
Save