int drm_client_modeset_create(struct drm_client_dev *client)
{ struct drm_device *dev = client->dev; unsignedint num_crtc = dev->mode_config.num_crtc; unsignedint max_connector_count = 1; struct drm_mode_set *modeset; struct drm_crtc *crtc; int i = 0;
/* Add terminating zero entry to enable index less iteration */
client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL); if (!client->modesets) return -ENOMEM;
staticbool drm_client_target_preferred(struct drm_device *dev, struct drm_connector *connectors[], unsignedint connector_count, conststruct drm_display_mode *modes[], struct drm_client_offset offsets[], bool enabled[], int width, int height)
{ const u64 mask = BIT_ULL(connector_count) - 1;
u64 conn_configured = 0; int tile_pass = 0; int num_tiled_conns = 0; int i;
for (i = 0; i < connector_count; i++) { if (connectors[i]->has_tile &&
connectors[i]->status == connector_status_connected)
num_tiled_conns++;
}
retry: for (i = 0; i < connector_count; i++) { struct drm_connector *connector = connectors[i]; constchar *mode_type;
if (conn_configured & BIT_ULL(i)) continue;
if (enabled[i] == false) {
conn_configured |= BIT_ULL(i); continue;
}
/* first pass over all the untiled connectors */ if (tile_pass == 0 && connector->has_tile) continue;
if (tile_pass == 1) { if (connector->tile_h_loc != 0 ||
connector->tile_v_loc != 0) continue;
} else { if (connector->tile_h_loc != tile_pass - 1 &&
connector->tile_v_loc != tile_pass - 1) /* if this tile_pass doesn't cover any of the tiles - keep going */ continue;
/* * find the tile offsets for this pass - need to find * all tiles left and above
*/
drm_client_get_tile_offsets(dev, connectors, connector_count,
modes, offsets, i,
connector->tile_h_loc, connector->tile_v_loc);
}
if (!modes[i]) {
mode_type = "first";
mode_replace(dev, &modes[i],
drm_connector_first_mode(connector));
}
/* * In case of tiled mode if all tiles not present fallback to * first available non tiled mode. * After all tiles are present, try to find the tiled mode * for all and if tiled mode not present due to fbcon size * limitations, use first non tiled mode only for * tile 0,0 and set to no mode for all other tiles.
*/ if (connector->has_tile) { if (num_tiled_conns <
connector->num_h_tile * connector->num_v_tile ||
(connector->tile_h_loc == 0 &&
connector->tile_v_loc == 0 &&
!drm_connector_get_tiled_mode(connector))) {
mode_type = "non tiled";
mode_replace(dev, &modes[i],
drm_connector_fallback_non_tiled_mode(connector));
} else {
mode_type = "tiled";
mode_replace(dev, &modes[i],
drm_connector_get_tiled_mode(connector));
}
}
if (modes[i])
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] found %s mode: %s\n",
connector->base.id, connector->name,
mode_type, modes[i]->name); else
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] no mode found\n",
connector->base.id, connector->name);
crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL); if (!crtcs) return best_score;
my_score = 1; if (connector->status == connector_status_connected)
my_score++; if (connector->cmdline_mode.specified)
my_score++; if (drm_connector_preferred_mode(connector, width, height))
my_score++;
/* * select a crtc for this connector and then attempt to configure * remaining connectors
*/
drm_client_for_each_modeset(modeset, client) { struct drm_crtc *crtc = modeset->crtc; int o;
if (!connector_has_possible_crtc(connector, crtc)) continue;
for (o = 0; o < n; o++) if (best_crtcs[o] == crtc) break;
if (o < n) { /* ignore cloning unless only a single crtc */ if (dev->mode_config.num_crtc > 1) continue;
if (!drm_mode_equal(modes[o], modes[n])) continue;
}
/* Try to read the BIOS display configuration and use it for the initial config */ staticbool drm_client_firmware_config(struct drm_client_dev *client, struct drm_connector *connectors[], unsignedint connector_count, struct drm_crtc *crtcs[], conststruct drm_display_mode *modes[], struct drm_client_offset offsets[], bool enabled[], int width, int height)
{ constint count = min_t(unsignedint, connector_count, BITS_PER_LONG); unsignedlong conn_configured, conn_seq, mask; struct drm_device *dev = client->dev; int i; bool *save_enabled; bool fallback = true, ret = true; int num_connectors_enabled = 0; int num_connectors_detected = 0; int num_tiled_conns = 0; struct drm_modeset_acquire_ctx ctx;
if (!drm_drv_uses_atomic_modeset(dev)) returnfalse;
if (drm_WARN_ON(dev, count <= 0)) returnfalse;
save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL); if (!save_enabled) returnfalse;
drm_modeset_acquire_init(&ctx, 0);
while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
drm_modeset_backoff(&ctx);
memcpy(save_enabled, enabled, count);
mask = GENMASK(count - 1, 0);
conn_configured = 0; for (i = 0; i < count; i++) { if (connectors[i]->has_tile &&
connectors[i]->status == connector_status_connected)
num_tiled_conns++;
}
retry:
conn_seq = conn_configured; for (i = 0; i < count; i++) { struct drm_connector *connector = connectors[i]; struct drm_encoder *encoder; struct drm_crtc *crtc; constchar *mode_type; int j;
if (conn_configured & BIT(i)) continue;
if (conn_seq == 0 && !connector->has_tile) continue;
if (connector->status == connector_status_connected)
num_connectors_detected++;
if (!enabled[i]) {
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] not enabled, skipping\n",
connector->base.id, connector->name);
conn_configured |= BIT(i); continue;
}
if (connector->force == DRM_FORCE_OFF) {
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] disabled by user, skipping\n",
connector->base.id, connector->name);
enabled[i] = false; continue;
}
encoder = connector->state->best_encoder; if (!encoder || drm_WARN_ON(dev, !connector->state->crtc)) { if (connector->force > DRM_FORCE_OFF) goto bail;
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] has no encoder or crtc, skipping\n",
connector->base.id, connector->name);
enabled[i] = false;
conn_configured |= BIT(i); continue;
}
num_connectors_enabled++;
crtc = connector->state->crtc;
/* * Make sure we're not trying to drive multiple connectors * with a single CRTC, since our cloning support may not * match the BIOS.
*/ for (j = 0; j < count; j++) { if (crtcs[j] == crtc) {
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] fallback: cloned configuration\n",
connector->base.id, connector->name); goto bail;
}
}
if (!modes[i]) {
mode_type = "first";
mode_replace(dev, &modes[i],
drm_connector_first_mode(connector));
}
/* last resort: use current mode */ if (!modes[i]) {
mode_type = "current";
mode_replace(dev, &modes[i],
&crtc->state->mode);
}
/* * In case of tiled modes, if all tiles are not present * then fallback to a non tiled mode.
*/ if (connector->has_tile &&
num_tiled_conns < connector->num_h_tile * connector->num_v_tile) {
mode_type = "non tiled";
mode_replace(dev, &modes[i],
drm_connector_fallback_non_tiled_mode(connector));
}
crtcs[i] = crtc;
drm_dbg_kms(dev, "[CONNECTOR::%d:%s] on [CRTC:%d:%s] using %s mode: %s\n",
connector->base.id, connector->name,
crtc->base.id, crtc->name,
mode_type, modes[i]->name);
for (i = 0; i < count; i++) { struct drm_connector *connector = connectors[i];
if (connector->has_tile)
drm_client_get_tile_offsets(dev, connectors, connector_count,
modes, offsets, i,
connector->tile_h_loc, connector->tile_v_loc);
}
/* * If the BIOS didn't enable everything it could, fall back to have the * same user experiencing of lighting up as much as possible like the * fbdev helper library.
*/ if (num_connectors_enabled != num_connectors_detected &&
num_connectors_enabled < dev->mode_config.num_crtc) {
drm_dbg_kms(dev, "fallback: Not all outputs enabled\n");
drm_dbg_kms(dev, "Enabled: %i, detected: %i\n",
num_connectors_enabled, num_connectors_detected);
fallback = true;
}
if (fallback) {
bail:
drm_dbg_kms(dev, "Not using firmware configuration\n");
memcpy(enabled, save_enabled, count);
ret = false;
}
mutex_lock(&dev->mode_config.mutex); for (i = 0; i < connector_count; i++)
total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height); if (!total_modes_count)
drm_dbg_kms(dev, "No connectors reported connected with modes\n");
drm_client_connectors_enabled(connectors, connector_count, enabled);
/** * drm_client_rotation() - Check the initial rotation value * @modeset: DRM modeset * @rotation: Returned rotation value * * This function checks if the primary plane in @modeset can hw rotate * to match the rotation needed on its connector. * * Note: Currently only 0 and 180 degrees are supported. * * Return: * True if the plane can do the rotation, false otherwise.
*/ bool drm_client_rotation(struct drm_mode_set *modeset, unsignedint *rotation)
{ struct drm_connector *connector = modeset->connectors[0]; struct drm_plane *plane = modeset->crtc->primary; struct drm_cmdline_mode *cmdline;
u64 valid_mask = 0; int i;
if (!modeset->num_connectors) returnfalse;
switch (connector->display_info.panel_orientation) { case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
*rotation = DRM_MODE_ROTATE_180; break; case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
*rotation = DRM_MODE_ROTATE_90; break; case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
*rotation = DRM_MODE_ROTATE_270; break; default:
*rotation = DRM_MODE_ROTATE_0;
}
/** * The panel already defined the default rotation * through its orientation. Whatever has been provided * on the command line needs to be added to that. * * Unfortunately, the rotations are at different bit * indices, so the math to add them up are not as * trivial as they could. * * Reflections on the other hand are pretty trivial to deal with, a * simple XOR between the two handle the addition nicely.
*/
cmdline = &connector->cmdline_mode; if (cmdline->specified && cmdline->rotation_reflection) { unsignedint cmdline_rest, panel_rest; unsignedint cmdline_rot, panel_rot; unsignedint sum_rot, sum_rest;
/* * TODO: support 90 / 270 degree hardware rotation, * depending on the hardware this may require the framebuffer * to be in a specific tiling format.
*/ if (((*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0 &&
(*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_180) ||
!plane->rotation_property) returnfalse;
for (i = 0; i < plane->rotation_property->num_values; i++)
valid_mask |= (1ULL << plane->rotation_property->values[i]);
if (drm_client_rotation(mode_set, &rotation)) { struct drm_plane_state *plane_state;
/* Cannot fail as we've already gotten the plane state above */
plane_state = drm_atomic_get_new_plane_state(state, primary);
plane_state->rotation = rotation;
}
ret = __drm_atomic_helper_set_config(mode_set, state); if (ret != 0) goto out_state;
/* * __drm_atomic_helper_set_config() sets active when a * mode is set, unconditionally clear it if we force DPMS off
*/ if (!active) { struct drm_crtc *crtc = mode_set->crtc; struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
crtc_state->active = false;
}
}
if (check)
ret = drm_atomic_check_only(state); else
ret = drm_atomic_commit(state);
/** * drm_client_modeset_commit_locked() - Force commit CRTC configuration * @client: DRM client * * Commit modeset configuration to crtcs without checking if there is a DRM * master. The assumption is that the caller already holds an internal DRM * master reference acquired with drm_master_internal_acquire(). * * Returns: * Zero on success or negative error code on failure.
*/ int drm_client_modeset_commit_locked(struct drm_client_dev *client)
{ struct drm_device *dev = client->dev; int ret;
mutex_lock(&client->modeset_mutex); if (drm_drv_uses_atomic_modeset(dev))
ret = drm_client_modeset_commit_atomic(client, true, false); else
ret = drm_client_modeset_commit_legacy(client);
mutex_unlock(&client->modeset_mutex);
/** * drm_client_modeset_dpms() - Set DPMS mode * @client: DRM client * @mode: DPMS mode * * Note: For atomic drivers @mode is reduced to on/off. * * Returns: * Zero on success or negative error code on failure.
*/ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
{ struct drm_device *dev = client->dev; int ret = 0;
if (!drm_master_internal_acquire(dev)) return -EBUSY;
mutex_lock(&client->modeset_mutex); if (drm_drv_uses_atomic_modeset(dev))
ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON, false); else
drm_client_modeset_dpms_legacy(client, mode);
mutex_unlock(&client->modeset_mutex);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.