for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
regmap_write(backend->engine.regs,
SUN4I_BACKEND_YGCOEF_REG(i),
sunxi_bt601_yuv2rgb_coef[i]);
/* * We should do that only for a single plane, but the * framebuffer's atomic_check has our back on this.
*/
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN,
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN);
/* TODO: Add support for the multi-planar YUV formats */ if (drm_format_info_is_yuv_packed(format) &&
drm_format_info_is_yuv_sampling_422(format))
val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; else
DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt);
/* * Allwinner seems to list the pixel sequence from right to left, while * DRM lists it from left to right.
*/ switch (fmt) { case DRM_FORMAT_YUYV:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY; break; case DRM_FORMAT_YVYU:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY; break; case DRM_FORMAT_UYVY:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU; break; case DRM_FORMAT_VYUY:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV; break; default:
DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n",
fmt);
}
/* Set the line width */
DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
regmap_write(backend->engine.regs,
SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
fb->pitches[0] * 8);
/* Get the start of the displayed memory */
dma_addr = drm_fb_dma_get_gem_addr(fb, state, 0);
DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &dma_addr);
if (fb->format->is_yuv) return sun4i_backend_update_yuv_buffer(backend, fb, dma_addr);
/* Write the 32 lower bits of the address (in bits) */
lo_paddr = dma_addr << 3;
DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
regmap_write(backend->engine.regs,
SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
lo_paddr);
/* And the upper bits */
hi_paddr = dma_addr >> 29;
DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr);
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
if (!sun4i_frontend_format_is_supported(format, modifier)) returnfalse;
if (!sun4i_backend_format_is_supported(format, modifier)) returntrue;
/* * TODO: The backend alone allows 2x and 4x integer scaling, including * support for an alpha component (which the frontend doesn't support). * Use the backend directly instead of the frontend in this case, with * another test to return false.
*/
if (sun4i_backend_plane_uses_scaler(state)) returntrue;
/* * Here the format is supported by both the frontend and the backend * and no frontend scaling is required, so use the backend directly.
*/ returnfalse;
}
if (!sun4i_backend_plane_is_supported(plane_state,
&layer_state->uses_frontend)) return -EINVAL;
if (layer_state->uses_frontend) {
DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
plane->index);
num_frontend_planes++;
} else { if (fb->format->is_yuv) {
DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
num_yuv_planes++;
}
}
DRM_DEBUG_DRIVER("Plane FB format is %p4cc\n",
&fb->format->format); if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
num_alpha_planes++;
DRM_DEBUG_DRIVER("Plane zpos is %d\n",
plane_state->normalized_zpos);
/* Sort our planes by Zpos */
plane_states[plane_state->normalized_zpos] = plane_state;
num_planes++;
}
/* All our planes were disabled, bail out */ if (!num_planes) return 0;
/* * The hardware is a bit unusual here. * * Even though it supports 4 layers, it does the composition * in two separate steps. * * The first one is assigning a layer to one of its two * pipes. If more that 1 layer is assigned to the same pipe, * and if pixels overlaps, the pipe will take the pixel from * the layer with the highest priority. * * The second step is the actual alpha blending, that takes * the two pipes as input, and uses the potential alpha * component to do the transparency between the two. * * This two-step scenario makes us unable to guarantee a * robust alpha blending between the 4 layers in all * situations, since this means that we need to have one layer * with alpha at the lowest position of our two pipes. * * However, we cannot even do that on every platform, since * the hardware has a bug where the lowest plane of the lowest * pipe (pipe 0, priority 0), if it has any alpha, will * discard the pixel data entirely and just display the pixels * in the background color (black by default). * * This means that on the affected platforms, we effectively * have only three valid configurations with alpha, all of * them with the alpha being on pipe1 with the lowest * position, which can be 1, 2 or 3 depending on the number of * planes and their zpos.
*/
/* For platforms that are not affected by the issue described above. */ if (backend->quirks->supports_lowest_plane_alpha)
num_alpha_planes_max++;
if (num_alpha_planes > num_alpha_planes_max) {
DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n"); return -EINVAL;
}
/* We can't have an alpha plane at the lowest position */ if (!backend->quirks->supports_lowest_plane_alpha &&
(plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)) return -EINVAL;
for (i = 1; i < num_planes; i++) { struct drm_plane_state *p_state = plane_states[i]; struct drm_framebuffer *fb = p_state->fb; struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(p_state);
/* * The only alpha position is the lowest plane of the * second pipe.
*/ if (fb->format->has_alpha || (p_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
current_pipe++;
s_state->pipe = current_pipe;
}
/* We can only have a single YUV plane at a time */ if (num_yuv_planes > SUN4I_BACKEND_NUM_YUV_PLANES) {
DRM_DEBUG_DRIVER("Too many planes with YUV, rejecting...\n"); return -EINVAL;
}
if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n"); return -EINVAL;
}
/* * In a teardown scenario with the frontend involved, we have * to keep the frontend enabled until the next vblank, and * only then disable it. * * This is due to the fact that the backend will not take into * account the new configuration (with the plane that used to * be fed by the frontend now disabled) until we write to the * commit bit and the hardware fetches the new configuration * during the next vblank. * * So we keep the frontend around in order to prevent any * visual artifacts.
*/
spin_lock(&backend->frontend_lock); if (backend->frontend_teardown) {
sun4i_frontend_exit(frontend);
backend->frontend_teardown = false;
}
spin_unlock(&backend->frontend_lock);
};
backend->sat_reset = devm_reset_control_get(dev, "sat"); if (IS_ERR(backend->sat_reset)) {
dev_err(dev, "Couldn't get the SAT reset line\n"); return PTR_ERR(backend->sat_reset);
}
ret = reset_control_deassert(backend->sat_reset); if (ret) {
dev_err(dev, "Couldn't deassert the SAT reset line\n"); return ret;
}
backend->sat_clk = devm_clk_get(dev, "sat"); if (IS_ERR(backend->sat_clk)) {
dev_err(dev, "Couldn't get our SAT clock\n");
ret = PTR_ERR(backend->sat_clk); goto err_assert_reset;
}
ret = clk_prepare_enable(backend->sat_clk); if (ret) {
dev_err(dev, "Couldn't enable the SAT clock\n"); return ret;
}
/* * The display backend can take video output from the display frontend, or * the display enhancement unit on the A80, as input for one it its layers. * This relationship within the display pipeline is encoded in the device * tree with of_graph, and we use it here to figure out which backend, if * there are 2 or more, we are currently probing. The number would be in * the "reg" property of the upstream output port endpoint.
*/ staticint sun4i_backend_of_get_id(struct device_node *node)
{ struct device_node *ep, *remote; struct of_endpoint of_ep;
/* Input port is 0, and we want the first endpoint. */
ep = of_graph_get_endpoint_by_regs(node, 0, -1); if (!ep) return -EINVAL;
remote = of_graph_get_remote_endpoint(ep);
of_node_put(ep); if (!remote) return -EINVAL;
if (of_property_present(dev->of_node, "interconnects")) { /* * This assume we have the same DMA constraints for all our the * devices in our pipeline (all the backends, but also the * frontends). This sounds bad, but it has always been the case * for us, and DRM doesn't do per-device allocation either, so * we would need to fix DRM first...
*/
ret = of_dma_configure(drm->dev, dev->of_node, true); if (ret) return ret;
}
backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node); if (IS_ERR(backend->frontend))
dev_warn(dev, "Couldn't find matching frontend, frontend features disabled\n");
regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs);
backend->reset = devm_reset_control_get(dev, NULL); if (IS_ERR(backend->reset)) {
dev_err(dev, "Couldn't get our reset line\n"); return PTR_ERR(backend->reset);
}
ret = reset_control_deassert(backend->reset); if (ret) {
dev_err(dev, "Couldn't deassert our reset line\n"); return ret;
}
backend->bus_clk = devm_clk_get(dev, "ahb"); if (IS_ERR(backend->bus_clk)) {
dev_err(dev, "Couldn't get the backend bus clock\n");
ret = PTR_ERR(backend->bus_clk); goto err_assert_reset;
}
clk_prepare_enable(backend->bus_clk);
backend->mod_clk = devm_clk_get(dev, "mod"); if (IS_ERR(backend->mod_clk)) {
dev_err(dev, "Couldn't get the backend module clock\n");
ret = PTR_ERR(backend->mod_clk); goto err_disable_bus_clk;
}
ret = clk_set_rate_exclusive(backend->mod_clk, 300000000); if (ret) {
dev_err(dev, "Couldn't set the module clock frequency\n"); goto err_disable_bus_clk;
}
clk_prepare_enable(backend->mod_clk);
backend->ram_clk = devm_clk_get(dev, "ram"); if (IS_ERR(backend->ram_clk)) {
dev_err(dev, "Couldn't get the backend RAM clock\n");
ret = PTR_ERR(backend->ram_clk); goto err_disable_mod_clk;
}
clk_prepare_enable(backend->ram_clk);
if (of_device_is_compatible(dev->of_node, "allwinner,sun8i-a33-display-backend")) {
ret = sun4i_backend_init_sat(dev); if (ret) {
dev_err(dev, "Couldn't init SAT resources\n"); goto err_disable_ram_clk;
}
}
backend->engine.regs = devm_regmap_init_mmio(dev, regs,
&sun4i_backend_regmap_config); if (IS_ERR(backend->engine.regs)) {
dev_err(dev, "Couldn't create the backend regmap\n"); return PTR_ERR(backend->engine.regs);
}
/* * Many of the backend's layer configuration registers have * undefined default values. This poses a risk as we use * regmap_update_bits in some places, and don't overwrite * the whole register. * * Clear the registers here to have something predictable.
*/ for (i = 0x800; i < 0x1000; i += 4)
regmap_write(backend->engine.regs, i, 0);
/* Enable the backend */
regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
SUN4I_BACKEND_MODCTL_DEBE_EN |
SUN4I_BACKEND_MODCTL_START_CTL);
/* Set output selection if needed */
quirks = of_device_get_match_data(dev); if (quirks->needs_output_muxing) { /* * We assume there is no dynamic muxing of backends * and TCONs, so we select the backend with same ID. * * While dynamic selection might be interesting, since * the CRTC is tied to the TCON, while the layers are * tied to the backends, this means, we will need to * switch between groups of layers. There might not be * a way to represent this constraint in DRM.
*/
regmap_update_bits(backend->engine.regs,
SUN4I_BACKEND_MODCTL_REG,
SUN4I_BACKEND_MODCTL_OUT_SEL,
(backend->engine.id
? SUN4I_BACKEND_MODCTL_OUT_LCD1
: SUN4I_BACKEND_MODCTL_OUT_LCD0));
}
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.