@@ -20,6 +20,7 @@
#include <linux/component.h>
#include <linux/list.h>
+#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/reset.h>
@@ -28,6 +29,11 @@
#include "sun4i_layer.h"
#include "sunxi_engine.h"
+struct sun4i_backend_quirks {
+ /* backend <-> TCON muxing selection done in backend */
+ bool needs_output_muxing;
+};
+
static const u32 sunxi_rgb2yuv_coef[12] = {
0x00000107, 0x00000204, 0x00000064, 0x00000108,
0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
@@ -345,6 +351,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct sun4i_drv *drv = drm->dev_private;
struct sun4i_backend *backend;
+ const struct sun4i_backend_quirks *quirks;
struct resource *res;
void __iomem *regs;
int i, ret;
@@ -439,6 +446,27 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
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));
+ }
+
return 0;
err_disable_ram_clk:
@@ -486,10 +514,28 @@ static int sun4i_backend_remove(struct platform_device *pdev)
return 0;
}
+static const struct sun4i_backend_quirks sun5i_backend_quirks = {
+};
+
+static const struct sun4i_backend_quirks sun6i_backend_quirks = {
+};
+
+static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
+};
+
static const struct of_device_id sun4i_backend_of_table[] = {
- { .compatible = "allwinner,sun5i-a13-display-backend" },
- { .compatible = "allwinner,sun6i-a31-display-backend" },
- { .compatible = "allwinner,sun8i-a33-display-backend" },
+ {
+ .compatible = "allwinner,sun5i-a13-display-backend",
+ .data = &sun5i_backend_quirks,
+ },
+ {
+ .compatible = "allwinner,sun6i-a31-display-backend",
+ .data = &sun6i_backend_quirks,
+ },
+ {
+ .compatible = "allwinner,sun8i-a33-display-backend",
+ .data = &sun8i_a33_backend_quirks,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
@@ -25,7 +25,8 @@
#define SUN4I_BACKEND_MODCTL_LINE_SEL BIT(29)
#define SUN4I_BACKEND_MODCTL_ITLMOD_EN BIT(28)
#define SUN4I_BACKEND_MODCTL_OUT_SEL GENMASK(22, 20)
-#define SUN4I_BACKEND_MODCTL_OUT_LCD (0 << 20)
+#define SUN4I_BACKEND_MODCTL_OUT_LCD0 (0 << 20)
+#define SUN4I_BACKEND_MODCTL_OUT_LCD1 (1 << 20)
#define SUN4I_BACKEND_MODCTL_OUT_FE0 (6 << 20)
#define SUN4I_BACKEND_MODCTL_OUT_FE1 (7 << 20)
#define SUN4I_BACKEND_MODCTL_HWC_EN BIT(16)
The backend has a mux to select the destination of the data to output to. It can select the TCON or the frontends. On the A20, it includes an option to output to the second TCON. This is not documented in the user manual, but the vendor kernel uses it nevertheless, so the second backend outputs to the second TCON. Although the muxing can be changed on the fly, DRM needs to be able to group a bunch of layers such that they get switched to another crtc together. This is because the display backend does the layer compositing, while the TCON generates the display timings. This constraint is not supported by DRM. Here we simply pair up backends and TCONs with the same ID. Signed-off-by: Chen-Yu Tsai <wens@csie.org> --- drivers/gpu/drm/sun4i/sun4i_backend.c | 52 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/sun4i/sun4i_backend.h | 3 +- 2 files changed, 51 insertions(+), 4 deletions(-)